use bevy_ecs::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Component)]
pub enum Dimension {
Auto,
Px(f32),
Percent(f32),
}
impl Dimension {
pub const fn length(val: f32) -> Self {
Self::Px(val)
}
pub const fn percent(val: f32) -> Self {
Self::Percent(val)
}
pub const fn auto() -> Self {
Self::Auto
}
pub const fn zero() -> Self {
Self::Px(0.0)
}
}
pub trait TaffyZero {
const ZERO: Self;
}
impl TaffyZero for Dimension {
const ZERO: Self = Self::Px(0.0);
}
pub trait TaffyAuto {
const AUTO: Self;
}
impl TaffyAuto for Dimension {
const AUTO: Self = Self::Auto;
}
impl Default for Dimension {
fn default() -> Self {
Self::Auto
}
}
impl From<Dimension> for taffy::Dimension {
fn from(val: Dimension) -> Self {
match val {
Dimension::Auto => taffy::Dimension::auto(),
Dimension::Px(v) => taffy::Dimension::length(v),
Dimension::Percent(v) => taffy::Dimension::percent(v / 100.0),
}
}
}
impl From<taffy::Dimension> for Dimension {
fn from(_val: taffy::Dimension) -> Self {
Self::Auto
}
}
#[derive(Debug, Clone, Copy, PartialEq, Component)]
pub enum LengthPercentageAuto {
Auto,
Px(f32),
Percent(f32),
}
impl LengthPercentageAuto {
pub const fn length(val: f32) -> Self {
Self::Px(val)
}
pub const fn percent(val: f32) -> Self {
Self::Percent(val)
}
pub const fn auto() -> Self {
Self::Auto
}
pub const fn zero() -> Self {
Self::Px(0.0)
}
}
impl TaffyZero for LengthPercentageAuto {
const ZERO: Self = Self::Px(0.0);
}
impl TaffyAuto for LengthPercentageAuto {
const AUTO: Self = Self::Auto;
}
impl Default for LengthPercentageAuto {
fn default() -> Self {
Self::Auto
}
}
impl From<LengthPercentageAuto> for taffy::LengthPercentageAuto {
fn from(val: LengthPercentageAuto) -> Self {
match val {
LengthPercentageAuto::Auto => taffy::LengthPercentageAuto::auto(),
LengthPercentageAuto::Px(v) => taffy::LengthPercentageAuto::length(v),
LengthPercentageAuto::Percent(v) => taffy::LengthPercentageAuto::percent(v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Component)]
pub enum LengthPercentage {
Px(f32),
Percent(f32),
}
impl LengthPercentage {
pub const fn length(val: f32) -> Self {
Self::Px(val)
}
pub const fn percent(val: f32) -> Self {
Self::Percent(val)
}
pub const fn zero() -> Self {
Self::Px(0.0)
}
}
impl TaffyZero for LengthPercentage {
const ZERO: Self = Self::Px(0.0);
}
impl Default for LengthPercentage {
fn default() -> Self {
Self::Px(0.0)
}
}
impl From<LengthPercentage> for taffy::LengthPercentage {
fn from(val: LengthPercentage) -> Self {
match val {
LengthPercentage::Px(v) => taffy::LengthPercentage::length(v),
LengthPercentage::Percent(v) => taffy::LengthPercentage::percent(v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Component)]
pub struct Rect<T> {
pub left: T,
pub right: T,
pub top: T,
pub bottom: T,
}
impl<T: TaffyZero> Rect<T> {
pub const fn zero() -> Self
where
T: Copy,
{
Self {
left: T::ZERO,
right: T::ZERO,
top: T::ZERO,
bottom: T::ZERO,
}
}
}
impl<T: TaffyAuto> Rect<T> {
pub const fn auto() -> Self
where
T: Copy,
{
Self {
left: T::AUTO,
right: T::AUTO,
top: T::AUTO,
bottom: T::AUTO,
}
}
}
impl<T: Default> Default for Rect<T> {
fn default() -> Self {
Self {
left: T::default(),
right: T::default(),
top: T::default(),
bottom: T::default(),
}
}
}
impl From<Rect<LengthPercentageAuto>> for taffy::Rect<taffy::LengthPercentageAuto> {
fn from(val: Rect<LengthPercentageAuto>) -> Self {
taffy::Rect {
left: val.left.into(),
right: val.right.into(),
top: val.top.into(),
bottom: val.bottom.into(),
}
}
}
impl From<Rect<LengthPercentage>> for taffy::Rect<taffy::LengthPercentage> {
fn from(val: Rect<LengthPercentage>) -> Self {
taffy::Rect {
left: val.left.into(),
right: val.right.into(),
top: val.top.into(),
bottom: val.bottom.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct BoxSize {
pub width: Option<Dimension>,
pub height: Option<Dimension>,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct BoxMargin(pub Rect<LengthPercentageAuto>);
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct BoxPadding(pub Rect<LengthPercentage>);
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum BoxPosition {
#[default]
Relative,
Absolute,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct BoxInset(pub Rect<LengthPercentageAuto>);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FlexContainer {
pub direction: taffy::FlexDirection,
pub justify_content: Option<taffy::JustifyContent>,
pub align_items: Option<taffy::AlignItems>,
}
impl Default for FlexContainer {
fn default() -> Self {
Self {
direction: taffy::FlexDirection::Row,
justify_content: None,
align_items: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FlexItem {
pub grow: f32,
pub shrink: f32,
pub basis: Dimension,
pub align_self: Option<taffy::AlignSelf>,
}
impl Default for FlexItem {
fn default() -> Self {
Self {
grow: 0.0,
shrink: 1.0,
basis: Dimension::Auto,
align_self: None,
}
}
}
pub use taffy::{AlignContent, AlignItems, AlignSelf, FlexDirection, JustifyContent};
#[derive(Component, Debug, Clone, Copy, PartialEq, Default)]
pub struct BoxStyle {
pub size: Option<BoxSize>,
pub min_size: Option<BoxSize>,
pub max_size: Option<BoxSize>,
pub margin: Option<BoxMargin>,
pub padding: Option<BoxPadding>,
pub position: Option<BoxPosition>,
pub inset: Option<BoxInset>,
pub flex_direction: Option<FlexDirection>,
pub justify_content: Option<JustifyContent>,
pub align_items: Option<AlignItems>,
pub flex_grow: Option<f32>,
pub flex_shrink: Option<f32>,
pub flex_basis: Option<Dimension>,
pub align_self: Option<AlignSelf>,
}
impl BoxStyle {
pub fn new() -> Self {
Self::default()
}
}
impl From<&BoxStyle> for taffy::Style {
fn from(style: &BoxStyle) -> Self {
let mut taffy_style = taffy::Style::default();
if let Some(size) = &style.size {
if let Some(w) = size.width {
taffy_style.size.width = w.into();
}
if let Some(h) = size.height {
taffy_style.size.height = h.into();
}
}
if let Some(min_size) = &style.min_size {
if let Some(w) = min_size.width {
taffy_style.min_size.width = w.into();
}
if let Some(h) = min_size.height {
taffy_style.min_size.height = h.into();
}
}
if let Some(max_size) = &style.max_size {
if let Some(w) = max_size.width {
taffy_style.max_size.width = w.into();
}
if let Some(h) = max_size.height {
taffy_style.max_size.height = h.into();
}
}
if let Some(margin) = &style.margin {
taffy_style.margin = margin.0.into();
}
if let Some(padding) = &style.padding {
taffy_style.padding = padding.0.into();
}
if let Some(position) = &style.position {
taffy_style.position = match position {
BoxPosition::Relative => taffy::Position::Relative,
BoxPosition::Absolute => taffy::Position::Absolute,
};
}
if let Some(inset) = &style.inset {
taffy_style.inset = inset.0.into();
}
if style.flex_direction.is_some()
|| style.justify_content.is_some()
|| style.align_items.is_some()
{
taffy_style.display = taffy::Display::Flex;
}
if let Some(dir) = style.flex_direction {
taffy_style.flex_direction = dir;
}
if let Some(jc) = style.justify_content {
taffy_style.justify_content = Some(jc);
}
if let Some(ai) = style.align_items {
taffy_style.align_items = Some(ai);
}
taffy_style.flex_grow = style.flex_grow.unwrap_or(0.0);
taffy_style.flex_shrink = style.flex_shrink.unwrap_or(1.0);
if let Some(basis) = style.flex_basis {
taffy_style.flex_basis = basis.into();
}
if let Some(align_self) = style.align_self {
taffy_style.align_self = Some(align_self);
}
taffy_style
}
}