use crate::align::{AlignX, AlignY};
use crate::engine;
#[derive(Debug, Clone, Copy, Default)]
pub struct CornerRadius {
pub top_left: f32,
pub top_right: f32,
pub bottom_left: f32,
pub bottom_right: f32,
}
impl CornerRadius {
pub fn is_zero(&self) -> bool {
self.top_left == 0.0
&& self.top_right == 0.0
&& self.bottom_left == 0.0
&& self.bottom_right == 0.0
}
}
impl From<f32> for CornerRadius {
fn from(value: f32) -> Self {
Self {
top_left: value,
top_right: value,
bottom_left: value,
bottom_right: value,
}
}
}
impl From<(f32, f32, f32, f32)> for CornerRadius {
fn from((tl, tr, br, bl): (f32, f32, f32, f32)) -> Self {
Self {
top_left: tl,
top_right: tr,
bottom_left: bl,
bottom_right: br,
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum SizingType {
Fit,
Grow,
Percent,
Fixed,
}
#[derive(Debug, Clone, Copy)]
pub enum Sizing {
Fit(f32, f32),
Grow(f32, f32),
Fixed(f32),
Percent(f32),
}
impl From<Sizing> for engine::SizingAxis {
fn from(value: Sizing) -> Self {
match value {
Sizing::Fit(min, max) => Self {
type_: engine::SizingType::Fit,
min_max: engine::SizingMinMax { min, max },
percent: 0.0,
},
Sizing::Grow(min, max) => Self {
type_: engine::SizingType::Grow,
min_max: engine::SizingMinMax { min, max },
percent: 0.0,
},
Sizing::Fixed(size) => Self {
type_: engine::SizingType::Fixed,
min_max: engine::SizingMinMax {
min: size,
max: size,
},
percent: 0.0,
},
Sizing::Percent(percent) => Self {
type_: engine::SizingType::Percent,
min_max: engine::SizingMinMax { min: 0.0, max: 0.0 },
percent,
},
}
}
}
#[derive(Debug, Default)]
pub struct Padding {
pub left: u16,
pub right: u16,
pub top: u16,
pub bottom: u16,
}
impl Padding {
pub fn new(left: u16, right: u16, top: u16, bottom: u16) -> Self {
Self {
left,
right,
top,
bottom,
}
}
pub fn all(value: u16) -> Self {
Self::new(value, value, value, value)
}
pub fn horizontal(value: u16) -> Self {
Self::new(value, value, 0, 0)
}
pub fn vertical(value: u16) -> Self {
Self::new(0, 0, value, value)
}
}
impl From<u16> for Padding {
fn from(value: u16) -> Self {
Self::all(value)
}
}
impl From<(u16, u16, u16, u16)> for Padding {
fn from((top, right, bottom, left): (u16, u16, u16, u16)) -> Self {
Self { left, right, top, bottom }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum LayoutDirection {
#[default]
LeftToRight,
TopToBottom,
}
pub struct LayoutBuilder {
pub(crate) config: engine::LayoutConfig,
}
impl LayoutBuilder {
#[inline]
pub fn gap(&mut self, gap: u16) -> &mut Self {
self.config.child_gap = gap;
self
}
#[inline]
pub fn align(&mut self, x: AlignX, y: AlignY) -> &mut Self {
self.config.child_alignment.x = x;
self.config.child_alignment.y = y;
self
}
#[inline]
pub fn direction(&mut self, direction: LayoutDirection) -> &mut Self {
self.config.layout_direction = direction;
self
}
#[inline]
pub fn padding(&mut self, padding: impl Into<Padding>) -> &mut Self {
let padding = padding.into();
self.config.padding.left = padding.left;
self.config.padding.right = padding.right;
self.config.padding.top = padding.top;
self.config.padding.bottom = padding.bottom;
self
}
}
#[macro_export]
macro_rules! fit {
($min:expr, $max:expr) => {
$crate::layout::Sizing::Fit($min, $max)
};
($min:expr) => {
fit!($min, f32::MAX)
};
() => {
fit!(0.0)
};
}
#[macro_export]
macro_rules! grow {
($min:expr, $max:expr) => {
$crate::layout::Sizing::Grow($min, $max)
};
($min:expr) => {
grow!($min, f32::MAX)
};
() => {
grow!(0.0)
};
}
#[macro_export]
macro_rules! fixed {
($val:expr) => {
$crate::layout::Sizing::Fixed($val)
};
}
#[macro_export]
macro_rules! percent {
($percent:expr) => {{
const _: () = assert!(
$percent >= 0.0 && $percent <= 1.0,
"Percent value must be between 0.0 and 1.0 inclusive!"
);
$crate::layout::Sizing::Percent($percent)
}};
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn fit_macro() {
let both_args = fit!(12.0, 34.0);
assert!(matches!(both_args, Sizing::Fit(12.0, 34.0)));
let one_arg = fit!(12.0);
assert!(matches!(one_arg, Sizing::Fit(12.0, f32::MAX)));
let zero_args = fit!();
assert!(matches!(zero_args, Sizing::Fit(0.0, f32::MAX)));
}
#[test]
fn grow_macro() {
let both_args = grow!(12.0, 34.0);
assert!(matches!(both_args, Sizing::Grow(12.0, 34.0)));
let one_arg = grow!(12.0);
assert!(matches!(one_arg, Sizing::Grow(12.0, f32::MAX)));
let zero_args = grow!();
assert!(matches!(zero_args, Sizing::Grow(0.0, f32::MAX)));
}
#[test]
fn fixed_macro() {
let value = fixed!(123.0);
assert!(matches!(value, Sizing::Fixed(123.0)));
}
#[test]
fn percent_macro() {
let value = percent!(0.5);
assert!(matches!(value, Sizing::Percent(0.5)));
}
}