415 lines
18 KiB
Rust
415 lines
18 KiB
Rust
/// Implements the various `Style` types used for computing Flexbox layouts,
|
|
/// along with appearance-based styles (`Color`s, etc).
|
|
|
|
#[cfg(feature="tokenize")]
|
|
use proc_macro2::{TokenStream, Ident, Span};
|
|
|
|
#[cfg(feature="tokenize")]
|
|
use quote::{quote, ToTokens};
|
|
|
|
pub use crate::color::Color;
|
|
|
|
pub use crate::stretch::geometry::{Point, Rect, Size};
|
|
pub use crate::stretch::number::Number;
|
|
pub use crate::stretch::result::Layout;
|
|
|
|
pub use crate::stretch::style::{
|
|
Style,
|
|
AlignContent, AlignItems, AlignSelf, Dimension, Direction, Display,
|
|
FlexDirection, JustifyContent, Overflow, PositionType, FlexWrap
|
|
};
|
|
|
|
/// Describes the backface-visibility for a view. This may be removed in a later release.
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum BackfaceVisibility {
|
|
Visible,
|
|
Hidden
|
|
}
|
|
|
|
impl Default for BackfaceVisibility {
|
|
fn default() -> BackfaceVisibility {
|
|
BackfaceVisibility::Visible
|
|
}
|
|
}
|
|
|
|
/// Describes a font style.
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum FontStyle {
|
|
Normal,
|
|
Italic,
|
|
Oblique
|
|
}
|
|
|
|
impl Default for FontStyle {
|
|
fn default() -> FontStyle {
|
|
FontStyle::Normal
|
|
}
|
|
}
|
|
|
|
/// Describes a font weight.
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum FontWeight {
|
|
Normal,
|
|
Bold
|
|
}
|
|
|
|
impl Default for FontWeight {
|
|
fn default() -> FontWeight {
|
|
FontWeight::Normal
|
|
}
|
|
}
|
|
|
|
/// Describes how text should be aligned.
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum TextAlignment {
|
|
Auto,
|
|
Left,
|
|
Right,
|
|
Center,
|
|
Justify
|
|
}
|
|
|
|
impl Default for TextAlignment {
|
|
fn default() -> TextAlignment {
|
|
TextAlignment::Auto
|
|
}
|
|
}
|
|
|
|
/// Describes a border style.
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum BorderStyle {
|
|
None, // The CSS value is None, but it's a reserved term in Rust ;P
|
|
Hidden,
|
|
Solid
|
|
}
|
|
|
|
impl Default for BorderStyle {
|
|
fn default() -> BorderStyle {
|
|
BorderStyle::None
|
|
}
|
|
}
|
|
|
|
/// Describes how a Font Family
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
pub enum FontFamily {
|
|
SansSerif // @TODO This is tricky because of &str/String/Copy. Revisit later.
|
|
}
|
|
|
|
impl Default for FontFamily {
|
|
fn default() -> Self {
|
|
FontFamily::SansSerif
|
|
}
|
|
}
|
|
|
|
/// When applying layout to a backing view, you'll get two calls - one with a `Layout`,
|
|
/// which contains the computed frame, and one with an `Appearance`, which contains things
|
|
/// like colors, fonts, and so on.
|
|
pub struct Appearance {
|
|
pub background_color: Color,
|
|
pub font_size: f32,
|
|
pub font_style: FontStyle,
|
|
pub font_weight: FontWeight,
|
|
pub opacity: f32,
|
|
pub text_alignment: TextAlignment,
|
|
pub text_color: Color,
|
|
pub text_decoration_color: Color,
|
|
pub text_shadow_color: Color,
|
|
pub tint_color: Color
|
|
}
|
|
|
|
impl Default for Appearance {
|
|
fn default() -> Appearance {
|
|
Appearance {
|
|
background_color: Color::transparent(),
|
|
// @TODO: We can definitely judge a default value better here.
|
|
font_size: 14.,
|
|
font_style: FontStyle::default(),
|
|
font_weight: FontWeight::default(),
|
|
opacity: 1.,
|
|
text_alignment: TextAlignment::default(),
|
|
text_color: Color::transparent(),
|
|
text_decoration_color: Color::transparent(),
|
|
text_shadow_color: Color::transparent(),
|
|
tint_color: Color::transparent()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// These exist purely for use in the parser code.
|
|
///
|
|
/// A `Style` is what's used for a node; `Styles` are what's parsed and stored.
|
|
/// At render-time, the rendering engine takes n styles and reduces them down into 1 `Style`
|
|
/// that's applied to the node in question.
|
|
#[derive(Debug)]
|
|
pub enum Styles {
|
|
AlignContent(AlignContent),
|
|
AlignItems(AlignItems),
|
|
AlignSelf(AlignSelf),
|
|
AspectRatio(Number),
|
|
BackfaceVisibility(BackfaceVisibility),
|
|
BackgroundColor(Color),
|
|
|
|
BorderColor(Color),
|
|
BorderEndColor(Color),
|
|
BorderBottomColor(Color),
|
|
BorderLeftColor(Color),
|
|
BorderRightColor(Color),
|
|
BorderTopColor(Color),
|
|
BorderStartColor(Color),
|
|
|
|
BorderStyle(BorderStyle),
|
|
BorderEndStyle(BorderStyle),
|
|
BorderBottomStyle(BorderStyle),
|
|
BorderLeftStyle(BorderStyle),
|
|
BorderRightStyle(BorderStyle),
|
|
BorderTopStyle(BorderStyle),
|
|
BorderStartStyle(BorderStyle),
|
|
|
|
BorderWidth(f32),
|
|
BorderEndWidth(f32),
|
|
BorderBottomWidth(f32),
|
|
BorderLeftWidth(f32),
|
|
BorderRightWidth(f32),
|
|
BorderTopWidth(f32),
|
|
BorderStartWidth(f32),
|
|
|
|
BorderRadius(f32),
|
|
BorderBottomEndRadius(f32),
|
|
BorderBottomLeftRadius(f32),
|
|
BorderBottomRightRadius(f32),
|
|
BorderBottomStartRadius(f32),
|
|
BorderTopLeftRadius(f32),
|
|
BorderTopRightRadius(f32),
|
|
BorderTopEndRadius(f32),
|
|
BorderTopStartRadius(f32),
|
|
|
|
Bottom(f32),
|
|
Direction(Direction),
|
|
Display(Display),
|
|
End(f32),
|
|
FlexBasis(f32),
|
|
FlexDirection(FlexDirection),
|
|
FlexGrow(f32),
|
|
FlexShrink(f32),
|
|
FlexWrap(FlexWrap),
|
|
FontFamily(FontFamily),
|
|
FontLineHeight(f32),
|
|
FontSize(f32),
|
|
FontStyle(FontStyle),
|
|
FontWeight(FontWeight),
|
|
Height(f32),
|
|
JustifyContent(JustifyContent),
|
|
Left(f32),
|
|
MarginBottom(f32),
|
|
MarginEnd(f32),
|
|
MarginLeft(f32),
|
|
MarginRight(f32),
|
|
MarginStart(f32),
|
|
MarginTop(f32),
|
|
MaxHeight(f32),
|
|
MaxWidth(f32),
|
|
MinHeight(f32),
|
|
MinWidth(f32),
|
|
Opacity(f32),
|
|
Overflow(Overflow),
|
|
PaddingBottom(f32),
|
|
PaddingEnd(f32),
|
|
PaddingLeft(f32),
|
|
PaddingRight(f32),
|
|
PaddingStart(f32),
|
|
PaddingTop(f32),
|
|
PositionType(PositionType),
|
|
Right(f32),
|
|
Start(f32),
|
|
TextAlignment(TextAlignment),
|
|
TextColor(Color),
|
|
TextDecorationColor(Color),
|
|
TextShadowColor(Color),
|
|
TintColor(Color),
|
|
Top(f32),
|
|
Width(f32)
|
|
}
|
|
|
|
/// A method for tokenizing a `Color` for a given attribute (e.g, `BackgroundColor`).
|
|
#[cfg(feature="tokenize")]
|
|
fn color_tokens(tokens: &mut TokenStream, color: &Color, style: &str) {
|
|
let red = color.red;
|
|
let green = color.green;
|
|
let blue = color.blue;
|
|
let alpha = color.alpha;
|
|
let s = Ident::new(style, Span::call_site());
|
|
|
|
tokens.extend(quote!(Styles::#s(Color {
|
|
red: #red,
|
|
green: #green,
|
|
blue: #blue,
|
|
alpha: #alpha
|
|
})));
|
|
}
|
|
|
|
/// Converts `Styles` into tokenized `Styles` representations, for use in the `styles! {}` macro.
|
|
#[cfg(feature="tokenize")]
|
|
impl ToTokens for Styles {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) { match self {
|
|
Styles::AlignContent(align_content) => { match align_content {
|
|
AlignContent::FlexStart => tokens.extend(quote!(Styles::AlignContent(AlignContent::FlexStart))),
|
|
AlignContent::FlexEnd => tokens.extend(quote!(Styles::AlignContent(AlignContent::FlexEnd))),
|
|
AlignContent::Center => tokens.extend(quote!(Styles::AlignContent(AlignContent::Center))),
|
|
AlignContent::Stretch => tokens.extend(quote!(Styles::AlignContent(AlignContent::Stretch))),
|
|
AlignContent::SpaceAround => tokens.extend(quote!(Styles::AlignContent(AlignContent::SpaceAround))),
|
|
AlignContent::SpaceBetween => tokens.extend(quote!(Styles::AlignContent(AlignContent::SpaceBetween)))
|
|
}},
|
|
|
|
Styles::AlignItems(align_items) => { match align_items {
|
|
AlignItems::FlexStart => tokens.extend(quote!(Styles::AlignItems(AlignItems::FlexStart))),
|
|
AlignItems::FlexEnd => tokens.extend(quote!(Styles::AlignItems(AlignItems::FlexEnd))),
|
|
AlignItems::Center => tokens.extend(quote!(Styles::AlignItems(AlignItems::Center))),
|
|
AlignItems::Baseline => tokens.extend(quote!(Styles::AlignItems(AlignItems::Baseline))),
|
|
AlignItems::Stretch => tokens.extend(quote!(Styles::AlignItems(AlignItems::Stretch)))
|
|
}},
|
|
|
|
Styles::AlignSelf(align_self) => { match align_self {
|
|
AlignSelf::Auto => tokens.extend(quote!(Styles::AlignSelf(AlignSelf::Auto))),
|
|
AlignSelf::FlexStart => tokens.extend(quote!(Styles::AlignSelf(AlignSelf::FlexStart))),
|
|
AlignSelf::FlexEnd => tokens.extend(quote!(Styles::AlignSelf(AlignSelf::FlexEnd))),
|
|
AlignSelf::Center => tokens.extend(quote!(Styles::AlignSelf(AlignSelf::Center))),
|
|
AlignSelf::Baseline => tokens.extend(quote!(Styles::AlignSelf(AlignSelf::Baseline))),
|
|
AlignSelf::Stretch => tokens.extend(quote!(Styles::AlignSelf(AlignSelf::Stretch)))
|
|
}},
|
|
|
|
Styles::AspectRatio(_) => {},
|
|
|
|
Styles::BackfaceVisibility(visibility) => { match visibility {
|
|
BackfaceVisibility::Visible => tokens.extend(quote!(Styles::BackfaceVisibility(BackfaceVisibility::Visible))),
|
|
BackfaceVisibility::Hidden => tokens.extend(quote!(Styles::BackfaceVisibility(BackfaceVisibility::Hidden)))
|
|
}},
|
|
|
|
Styles::BackgroundColor(color) => color_tokens(tokens, color, "BackgroundColor"),
|
|
Styles::BorderColor(color) => color_tokens(tokens, color, "BorderColor"),
|
|
Styles::BorderEndColor(color) => color_tokens(tokens, color, "BorderEndColor"),
|
|
Styles::BorderBottomColor(color) => color_tokens(tokens, color, "BorderBottomColor"),
|
|
Styles::BorderLeftColor(color) => color_tokens(tokens, color, "BorderLeftColor"),
|
|
Styles::BorderRightColor(color) => color_tokens(tokens, color, "BorderRightColor"),
|
|
Styles::BorderTopColor(color) => color_tokens(tokens, color, "BorderTopColor"),
|
|
Styles::BorderStartColor(color) => color_tokens(tokens, color, "BorderStartColor"),
|
|
Styles::BorderStyle(_) => {},
|
|
Styles::BorderEndStyle(_) => {},
|
|
Styles::BorderBottomStyle(_) => {},
|
|
Styles::BorderLeftStyle(_) => {},
|
|
Styles::BorderRightStyle(_) => {},
|
|
Styles::BorderTopStyle(_) => {},
|
|
Styles::BorderStartStyle(_) => {},
|
|
Styles::BorderWidth(border_width) => tokens.extend(quote!(Styles::BorderWidth(#border_width))),
|
|
Styles::BorderEndWidth(border_end_width) => tokens.extend(quote!(Styles::BorderEndWidth(#border_end_width))),
|
|
Styles::BorderBottomWidth(border_bottom_width) => tokens.extend(quote!(Styles::BorderBottomWidth(#border_bottom_width))),
|
|
Styles::BorderLeftWidth(border_left_width) => tokens.extend(quote!(Styles::BorderLeftWidth(#border_left_width))),
|
|
Styles::BorderRightWidth(border_right_width) => tokens.extend(quote!(Styles::BorderRightWidth(#border_right_width))),
|
|
Styles::BorderTopWidth(border_top_width) => tokens.extend(quote!(Styles::BorderTopWidth(#border_top_width))),
|
|
Styles::BorderStartWidth(border_start_width) => tokens.extend(quote!(Styles::BorderStartWidth(#border_start_width))),
|
|
Styles::BorderRadius(border_radius) => tokens.extend(quote!(Styles::BorderRadius(#border_radius))),
|
|
Styles::BorderBottomEndRadius(border_bottom_end_radius) => tokens.extend(quote!(Styles::BorderBottomEndRadius(#border_bottom_end_radius))),
|
|
Styles::BorderBottomLeftRadius(border_bottom_left_radius) => tokens.extend(quote!(Styles::BorderBottomLeftRadius(#border_bottom_left_radius))),
|
|
Styles::BorderBottomRightRadius(border_bottom_right_radius) => tokens.extend(quote!(Styles::BorderBottomRightRadius(#border_bottom_right_radius))),
|
|
Styles::BorderBottomStartRadius(border_bottom_start_radius) => tokens.extend(quote!(Styles::BorderBottomStartRadius(#border_bottom_start_radius))),
|
|
Styles::BorderTopLeftRadius(border_top_left_radius) => tokens.extend(quote!(Styles::BorderTopLeftRadius(#border_top_left_radius))),
|
|
Styles::BorderTopRightRadius(border_top_right_radius) => tokens.extend(quote!(Styles::BorderTopRightRadius(#border_top_right_radius))),
|
|
Styles::BorderTopEndRadius(border_top_end_radius) => tokens.extend(quote!(Styles::BorderTopEndRadius(#border_top_end_radius))),
|
|
Styles::BorderTopStartRadius(border_top_start_radius) => tokens.extend(quote!(Styles::BorderTopStartRadius(#border_top_start_radius))),
|
|
Styles::Bottom(bottom) => tokens.extend(quote!(Styles::Bottom(#bottom))),
|
|
|
|
Styles::Direction(direction) => { match direction {
|
|
Direction::Inherit => tokens.extend(quote!(Styles::Direction(Direction::Inherit))),
|
|
Direction::LTR => tokens.extend(quote!(Styles::Direction(Direction::LTR))),
|
|
Direction::RTL => tokens.extend(quote!(Styles::Direction(Direction::RTL)))
|
|
}},
|
|
|
|
Styles::Display(display) => { match display {
|
|
Display::Flex => tokens.extend(quote!(Styles::Display(Display::Flex))),
|
|
Display::None => tokens.extend(quote!(Styles::Display(Display::None)))
|
|
}},
|
|
|
|
Styles::End(end) => tokens.extend(quote!(Styles::End(#end))),
|
|
Styles::FlexBasis(flex_basis) => tokens.extend(quote!(Styles::FlexBasis(#flex_basis))),
|
|
|
|
Styles::FlexDirection(direction) => { match direction {
|
|
FlexDirection::Row => tokens.extend(quote!(Styles::FlexDirection(FlexDirection::Row))),
|
|
FlexDirection::Column => tokens.extend(quote!(Styles::FlexDirection(FlexDirection::Column))),
|
|
FlexDirection::RowReverse => tokens.extend(quote!(Styles::FlexDirection(FlexDirection::RowReverse))),
|
|
FlexDirection::ColumnReverse => tokens.extend(quote!(Styles::FlexDirection(FlexDirection::ColumnReverse)))
|
|
}},
|
|
|
|
Styles::FlexGrow(flex_grow) => tokens.extend(quote!(Styles::FlexGrow(#flex_grow))),
|
|
Styles::FlexShrink(flex_shrink) => tokens.extend(quote!(Styles::FlexShrink(#flex_shrink))),
|
|
|
|
Styles::FlexWrap(wrap) => { match wrap {
|
|
FlexWrap::NoWrap => tokens.extend(quote!(Styles::FlexWrap(FlexWrap::NoWrap))),
|
|
FlexWrap::Wrap => tokens.extend(quote!(Styles::FlexWrap(FlexWrap::Wrap))),
|
|
FlexWrap::WrapReverse => tokens.extend(quote!(Styles::FlexWrap(FlexWrap::WrapReverse)))
|
|
}},
|
|
|
|
Styles::FontFamily(_family) => {},
|
|
Styles::FontLineHeight(line_height) => tokens.extend(quote!(Styles::LineHeight(#line_height))),
|
|
Styles::FontSize(font_size) => tokens.extend(quote!(Styles::FontSize(#font_size))),
|
|
Styles::FontStyle(_style) => {},
|
|
Styles::FontWeight(_weight) => {},
|
|
Styles::Height(height) => tokens.extend(quote!(Styles::Height(#height))),
|
|
|
|
Styles::JustifyContent(justify) => { match justify {
|
|
JustifyContent::FlexStart => tokens.extend(quote!(Styles::JustifyContent(JustifyContent::FlexStart))),
|
|
JustifyContent::FlexEnd => tokens.extend(quote!(Styles::JustifyContent(JustifyContent::FlexEnd))),
|
|
JustifyContent::Center => tokens.extend(quote!(Styles::JustifyContent(JustifyContent::Center))),
|
|
JustifyContent::SpaceBetween => tokens.extend(quote!(Styles::JustifyContent(JustifyContent::SpaceBetween))),
|
|
JustifyContent::SpaceAround => tokens.extend(quote!(Styles::JustifyContent(JustifyContent::SpaceAround))),
|
|
JustifyContent::SpaceEvenly => tokens.extend(quote!(Styles::JustifyContent(JustifyContent::SpaceEvenly)))
|
|
}},
|
|
|
|
Styles::Left(left) => tokens.extend(quote!(Styles::Left(#left))),
|
|
Styles::MarginBottom(margin_bottom) => tokens.extend(quote!(Styles::MarginBottom(#margin_bottom))),
|
|
Styles::MarginEnd(margin_end) => tokens.extend(quote!(Styles::MarginEnd(#margin_end))),
|
|
Styles::MarginLeft(margin_left) => tokens.extend(quote!(Styles::MarginLeft(#margin_left))),
|
|
Styles::MarginRight(margin_right) => tokens.extend(quote!(Styles::MarginRight(#margin_right))),
|
|
Styles::MarginStart(margin_start) => tokens.extend(quote!(Styles::MarginStart(#margin_start))),
|
|
Styles::MarginTop(top) => tokens.extend(quote!(Styles::Top(#top))),
|
|
Styles::MaxHeight(max_height) => tokens.extend(quote!(Styles::MaxHeight(#max_height))),
|
|
Styles::MaxWidth(max_width) => tokens.extend(quote!(Styles::MaxWidth(#max_width))),
|
|
Styles::MinHeight(min_height) => tokens.extend(quote!(Styles::MinHeight(#min_height))),
|
|
Styles::MinWidth(min_width) => tokens.extend(quote!(Styles::MinWidth(#min_width))),
|
|
Styles::Opacity(opacity) => tokens.extend(quote!(Styles::Opacity(#opacity))),
|
|
|
|
Styles::Overflow(overflow) => { match overflow {
|
|
Overflow::Visible => tokens.extend(quote!(Styles::Overflow(Overflow::Visible))),
|
|
Overflow::Hidden => tokens.extend(quote!(Styles::Overflow(Overflow::Hidden))),
|
|
Overflow::Scroll => tokens.extend(quote!(Styles::Overflow(Overflow::Scroll)))
|
|
}},
|
|
|
|
Styles::PaddingBottom(padding_bottom) => tokens.extend(quote!(Styles::PaddingBottom(#padding_bottom))),
|
|
Styles::PaddingEnd(padding_end) => tokens.extend(quote!(Styles::PaddingEnd(#padding_end))),
|
|
Styles::PaddingLeft(padding_left) => tokens.extend(quote!(Styles::PaddingLeft(#padding_left))),
|
|
Styles::PaddingRight(padding_right) => tokens.extend(quote!(Styles::PaddingRight(#padding_right))),
|
|
Styles::PaddingStart(padding_start) => tokens.extend(quote!(Styles::PaddingStart(#padding_start))),
|
|
Styles::PaddingTop(padding_top) => tokens.extend(quote!(Styles::PaddingTop(#padding_top))),
|
|
|
|
Styles::PositionType(position_type) => { match position_type {
|
|
PositionType::Relative => tokens.extend(quote!(Styles::PositionType(PositionType::Relative))),
|
|
PositionType::Absolute => tokens.extend(quote!(Styles::PositionType(PositionType::Absolute)))
|
|
}},
|
|
|
|
Styles::Right(right) => tokens.extend(quote!(Styles::Right(#right))),
|
|
Styles::Start(start) => tokens.extend(quote!(Styles::Start(#start))),
|
|
|
|
Styles::TextAlignment(alignment) => { match alignment {
|
|
TextAlignment::Auto => tokens.extend(quote!(Styles::TextAlignment(TextAlignment::Auto))),
|
|
TextAlignment::Left => tokens.extend(quote!(Styles::TextAlignment(TextAlignment::Left))),
|
|
TextAlignment::Right => tokens.extend(quote!(Styles::TextAlignment(TextAlignment::Right))),
|
|
TextAlignment::Center => tokens.extend(quote!(Styles::TextAlignment(TextAlignment::Center))),
|
|
TextAlignment::Justify => tokens.extend(quote!(Styles::TextAlignment(TextAlignment::Justify)))
|
|
}},
|
|
|
|
Styles::TextColor(color) => color_tokens(tokens, color, "TextColor"),
|
|
Styles::TextDecorationColor(color) => color_tokens(tokens, color, "TextDecorationColor"),
|
|
Styles::TextShadowColor(color) => color_tokens(tokens, color, "TextShadowColor"),
|
|
Styles::TintColor(color) => color_tokens(tokens, color, "TintColor"),
|
|
Styles::Top(top) => tokens.extend(quote!(Styles::Top(#top))),
|
|
Styles::Width(width) => tokens.extend(quote!(Styles::Width(#width)))
|
|
}}
|
|
}
|