use crate::geometry::Size;
use crate::theme::{ColorValue, RadiusValue};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Length {
Px(f32),
Percent(f32),
Auto,
}
impl Length {
pub const fn px(value: f32) -> Length {
Length::Px(value)
}
pub const fn pct(percent: f32) -> Length {
Length::Percent(percent)
}
pub const fn auto() -> Length {
Length::Auto
}
}
pub const fn px(value: f32) -> Length {
Length::px(value)
}
pub const fn pct(percent: f32) -> Length {
Length::pct(percent)
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Edges<T> {
pub top: T,
pub right: T,
pub bottom: T,
pub left: T,
}
impl<T: Copy> Edges<T> {
pub const fn all(value: T) -> Edges<T> {
Edges {
top: value,
right: value,
bottom: value,
left: value,
}
}
pub const fn xy(x: T, y: T) -> Edges<T> {
Edges {
top: y,
right: x,
bottom: y,
left: x,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Direction {
Row,
Column,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Align {
Start,
End,
Center,
Stretch,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Justify {
Start,
End,
Center,
SpaceBetween,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Position {
Relative,
Absolute,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Display {
Flex,
Block,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Overflow {
Visible,
Clip,
}
#[derive(Clone, Debug, PartialEq)]
pub struct LayoutProps {
pub display: Display,
pub hidden: bool,
pub direction: Direction,
pub wrap: bool,
pub grow: f32,
pub shrink: f32,
pub basis: Length,
pub width: Length,
pub height: Length,
pub min_width: Length,
pub min_height: Length,
pub max_width: Length,
pub max_height: Length,
pub padding: Edges<Length>,
pub margin: Edges<Length>,
pub gap: Size,
pub align_items: Option<Align>,
pub justify_content: Option<Justify>,
pub position: Position,
pub inset: Edges<Length>,
pub border_width: Edges<f32>,
pub overflow: Overflow,
}
impl Default for LayoutProps {
fn default() -> LayoutProps {
LayoutProps {
display: Display::Flex,
hidden: false,
direction: Direction::Row,
wrap: false,
grow: 0.0,
shrink: 1.0,
basis: Length::Auto,
width: Length::Auto,
height: Length::Auto,
min_width: Length::Auto,
min_height: Length::Auto,
max_width: Length::Auto,
max_height: Length::Auto,
padding: Edges::all(Length::px(0.0)),
margin: Edges::all(Length::px(0.0)),
gap: Size::default(),
align_items: None,
justify_content: None,
position: Position::Relative,
inset: Edges::all(Length::auto()),
border_width: Edges::all(0.0),
overflow: Overflow::Visible,
}
}
}
impl LayoutProps {
pub(crate) fn to_taffy(&self) -> taffy::Style {
let overflow = match self.overflow {
Overflow::Visible => taffy::Overflow::Visible,
Overflow::Clip => taffy::Overflow::Clip,
};
let mut style: taffy::Style = taffy::Style::DEFAULT;
style.display = match (self.hidden, self.display) {
(true, _) => taffy::Display::None,
(false, Display::Flex) => taffy::Display::Flex,
(false, Display::Block) => taffy::Display::Block,
};
style.flex_direction = match self.direction {
Direction::Row => taffy::FlexDirection::Row,
Direction::Column => taffy::FlexDirection::Column,
};
style.flex_wrap = if self.wrap {
taffy::FlexWrap::Wrap
} else {
taffy::FlexWrap::NoWrap
};
style.flex_grow = self.grow;
style.flex_shrink = self.shrink;
style.flex_basis = to_dimension(self.basis);
style.size = taffy::Size {
width: to_dimension(self.width),
height: to_dimension(self.height),
};
style.min_size = taffy::Size {
width: to_length_percentage_auto(self.min_width),
height: to_length_percentage_auto(self.min_height),
};
style.max_size = taffy::Size {
width: to_length_percentage_auto(self.max_width),
height: to_length_percentage_auto(self.max_height),
};
style.padding = to_taffy_edges(self.padding, to_length_percentage);
style.margin = to_taffy_edges(self.margin, to_length_percentage_auto);
style.gap = taffy::Size {
width: taffy::LengthPercentage::length(self.gap.width),
height: taffy::LengthPercentage::length(self.gap.height),
};
style.align_items = match self.align_items {
None => taffy::AlignItems::NORMAL,
Some(Align::Start) => taffy::AlignItems::START,
Some(Align::End) => taffy::AlignItems::END,
Some(Align::Center) => taffy::AlignItems::CENTER,
Some(Align::Stretch) => taffy::AlignItems::STRETCH,
};
style.justify_content = match self.justify_content {
None => taffy::JustifyContent::NORMAL,
Some(Justify::Start) => taffy::JustifyContent::START,
Some(Justify::End) => taffy::JustifyContent::END,
Some(Justify::Center) => taffy::JustifyContent::CENTER,
Some(Justify::SpaceBetween) => taffy::JustifyContent::SPACE_BETWEEN,
};
style.position = match self.position {
Position::Relative => taffy::Position::Relative,
Position::Absolute => taffy::Position::Absolute,
};
style.inset = to_taffy_edges(self.inset, to_length_percentage_auto);
style.border = to_taffy_edges(self.border_width, taffy::LengthPercentage::length);
style.overflow = taffy::Point {
x: overflow,
y: overflow,
};
style
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct PaintProps {
pub background: Option<ColorValue>,
pub border_color: Option<ColorValue>,
pub text_color: Option<ColorValue>,
pub corner_radius: RadiusValue,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Style {
pub layout: LayoutProps,
pub paint: PaintProps,
}
fn to_dimension(length: Length) -> taffy::Dimension {
match length {
Length::Px(value) => taffy::Dimension::length(value),
Length::Percent(percent) => taffy::Dimension::percent(percent / 100.0),
Length::Auto => taffy::Dimension::auto(),
}
}
fn to_length_percentage(length: Length) -> taffy::LengthPercentage {
match length {
Length::Px(value) => taffy::LengthPercentage::length(value),
Length::Percent(percent) => taffy::LengthPercentage::percent(percent / 100.0),
Length::Auto => taffy::LengthPercentage::length(0.0),
}
}
fn to_length_percentage_auto(length: Length) -> taffy::LengthPercentageAuto {
match length {
Length::Px(value) => taffy::LengthPercentageAuto::length(value),
Length::Percent(percent) => taffy::LengthPercentageAuto::percent(percent / 100.0),
Length::Auto => taffy::LengthPercentageAuto::auto(),
}
}
fn to_taffy_edges<T: Copy, U>(edges: Edges<T>, convert: impl Fn(T) -> U) -> taffy::Rect<U> {
taffy::Rect {
left: convert(edges.left),
right: convert(edges.right),
top: convert(edges.top),
bottom: convert(edges.bottom),
}
}
#[cfg(test)]
#[path = "style_tests.rs"]
mod tests;