use cranpose_core::NodeId;
use super::layout::{LayoutEnvironment, compose_layout};
use crate::{composable, layout::flex_box::FlexBoxMeasurePolicy, modifier::Modifier};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlexDirection {
#[default]
Row,
RowReverse,
Column,
ColumnReverse,
}
impl FlexDirection {
pub(crate) fn is_horizontal(self) -> bool {
matches!(self, Self::Row | Self::RowReverse)
}
pub(crate) fn is_reverse(self) -> bool {
matches!(self, Self::RowReverse | Self::ColumnReverse)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlexWrap {
#[default]
NoWrap,
Wrap,
WrapReverse,
}
impl FlexWrap {
pub(crate) fn wraps(self) -> bool {
self != Self::NoWrap
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlexJustifyContent {
#[default]
Start,
End,
Center,
SpaceBetween,
SpaceAround,
SpaceEvenly,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlexAlignItems {
#[default]
Start,
End,
Center,
Stretch,
Baseline,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlexAlignSelf {
#[default]
Auto,
Start,
End,
Center,
Stretch,
Baseline,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlexAlignContent {
#[default]
Start,
End,
Center,
Stretch,
SpaceBetween,
SpaceAround,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum FlexBasis {
#[default]
Auto,
Dp(f32),
Percent(f32),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FlexBoxConfig {
pub(crate) direction: FlexDirection,
pub(crate) wrap: FlexWrap,
pub(crate) justify_content: FlexJustifyContent,
pub(crate) align_items: FlexAlignItems,
pub(crate) align_content: FlexAlignContent,
pub(crate) max_items_in_each_line: usize,
pub(crate) row_gap: f32,
pub(crate) column_gap: f32,
}
impl Default for FlexBoxConfig {
fn default() -> Self {
Self {
direction: FlexDirection::Row,
wrap: FlexWrap::NoWrap,
justify_content: FlexJustifyContent::Start,
align_items: FlexAlignItems::Start,
align_content: FlexAlignContent::Start,
max_items_in_each_line: usize::MAX,
row_gap: 0.0,
column_gap: 0.0,
}
}
}
impl FlexBoxConfig {
pub fn new() -> Self {
Self::default()
}
pub fn direction(mut self, direction: FlexDirection) -> Self {
self.direction = direction;
self
}
pub fn wrap(mut self, wrap: FlexWrap) -> Self {
self.wrap = wrap;
self
}
pub fn justify_content(mut self, justify: FlexJustifyContent) -> Self {
self.justify_content = justify;
self
}
pub fn align_items(mut self, align: FlexAlignItems) -> Self {
self.align_items = align;
self
}
pub fn align_content(mut self, align: FlexAlignContent) -> Self {
self.align_content = align;
self
}
pub fn max_items_in_each_line(mut self, count: usize) -> Self {
self.max_items_in_each_line = count.max(1);
self
}
pub fn row_gap(mut self, gap: f32) -> Self {
self.row_gap = gap.max(0.0);
self
}
pub fn column_gap(mut self, gap: f32) -> Self {
self.column_gap = gap.max(0.0);
self
}
pub fn gap(self, all: f32) -> Self {
self.row_gap(all).column_gap(all)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FlexConfig {
pub(crate) align_self: FlexAlignSelf,
pub(crate) order: i32,
pub(crate) grow: Option<f32>,
pub(crate) shrink: f32,
pub(crate) basis: FlexBasis,
}
impl Default for FlexConfig {
fn default() -> Self {
Self {
align_self: FlexAlignSelf::Auto,
order: 0,
grow: None,
shrink: 1.0,
basis: FlexBasis::Auto,
}
}
}
impl FlexConfig {
pub fn new() -> Self {
Self::default()
}
pub fn align_self(mut self, align: FlexAlignSelf) -> Self {
self.align_self = align;
self
}
pub fn order(mut self, order: i32) -> Self {
self.order = order;
self
}
pub fn grow(mut self, grow: f32) -> Self {
self.grow = Some(grow.max(0.0));
self
}
pub fn shrink(mut self, shrink: f32) -> Self {
self.shrink = shrink.max(0.0);
self
}
pub fn basis(mut self, basis: FlexBasis) -> Self {
self.basis = basis;
self
}
}
impl Modifier {
pub fn flex(self, config: FlexConfig) -> Self {
self.layout_data(config)
}
}
#[composable]
pub fn FlexBox<F>(modifier: Modifier, config: FlexBoxConfig, content: F) -> NodeId
where
F: FnMut() + 'static,
{
let environment = LayoutEnvironment::current();
let policy = FlexBoxMeasurePolicy {
config,
layout_direction: environment.direction,
density: environment.density.density(),
};
compose_layout(modifier, policy, environment, content)
}