use crate::{layout, types::*, Cache, LayoutWrap};
pub trait Node: Sized {
type Store;
type Tree;
type ChildIter<'t>: Iterator<Item = &'t Self>
where
Self: 't;
type CacheKey: std::fmt::Debug;
type SubLayout<'a>;
fn layout<C: Cache<Node = Self>>(
&self,
cache: &mut C,
tree: &Self::Tree,
store: &Self::Store,
sublayout: &mut Self::SubLayout<'_>,
) -> Size {
let width = self.width(store).unwrap_or(Units::Pixels(0.0)).to_px(0.0, 0.0);
let height = self.height(store).unwrap_or(Units::Pixels(0.0)).to_px(0.0, 0.0);
cache.set_bounds(self, cache.posx(self), cache.posy(self), width, height);
let layout_type = self.layout_type(store).unwrap_or_default();
let (parent_main, parent_cross) = match layout_type {
LayoutType::Row | LayoutType::Grid => (width, height), LayoutType::Column => (height, width), };
layout(self, layout_type, parent_main, parent_cross, cache, tree, store, sublayout)
}
fn key(&self) -> Self::CacheKey;
fn children<'t>(&'t self, tree: &'t Self::Tree) -> Self::ChildIter<'t>;
fn visible(&self, store: &Self::Store) -> bool;
fn layout_type(&self, store: &Self::Store) -> Option<LayoutType>;
fn position_type(&self, store: &Self::Store) -> Option<PositionType>;
fn direction(&self, _store: &Self::Store) -> Option<Direction> {
None
}
fn wrap(&self, _store: &Self::Store) -> Option<LayoutWrap> {
None
}
fn alignment(&self, store: &Self::Store) -> Option<Alignment>;
fn width(&self, store: &Self::Store) -> Option<Units>;
fn height(&self, store: &Self::Store) -> Option<Units>;
fn left(&self, store: &Self::Store) -> Option<Units>;
fn right(&self, store: &Self::Store) -> Option<Units>;
fn top(&self, store: &Self::Store) -> Option<Units>;
fn bottom(&self, store: &Self::Store) -> Option<Units>;
fn content_size(
&self,
store: &Self::Store,
sublayout: &mut Self::SubLayout<'_>,
parent_width: Option<f32>,
parent_height: Option<f32>,
) -> Option<(f32, f32)>;
fn padding_left(&self, store: &Self::Store) -> Option<Units>;
fn padding_right(&self, store: &Self::Store) -> Option<Units>;
fn padding_top(&self, store: &Self::Store) -> Option<Units>;
fn padding_bottom(&self, store: &Self::Store) -> Option<Units>;
fn vertical_gap(&self, store: &Self::Store) -> Option<Units>;
fn horizontal_gap(&self, store: &Self::Store) -> Option<Units>;
fn min_vertical_gap(&self, store: &Self::Store) -> Option<Units>;
fn min_horizontal_gap(&self, store: &Self::Store) -> Option<Units>;
fn max_vertical_gap(&self, store: &Self::Store) -> Option<Units>;
fn max_horizontal_gap(&self, store: &Self::Store) -> Option<Units>;
fn min_width(&self, store: &Self::Store) -> Option<Units>;
fn min_height(&self, store: &Self::Store) -> Option<Units>;
fn max_width(&self, store: &Self::Store) -> Option<Units>;
fn max_height(&self, store: &Self::Store) -> Option<Units>;
fn border_left(&self, store: &Self::Store) -> Option<Units>;
fn border_right(&self, store: &Self::Store) -> Option<Units>;
fn border_top(&self, store: &Self::Store) -> Option<Units>;
fn border_bottom(&self, store: &Self::Store) -> Option<Units>;
fn vertical_scroll(&self, store: &Self::Store) -> Option<f32>;
fn horizontal_scroll(&self, store: &Self::Store) -> Option<f32>;
fn grid_columns(&self, store: &Self::Store) -> Option<Vec<Units>>;
fn grid_rows(&self, store: &Self::Store) -> Option<Vec<Units>>;
fn column_start(&self, store: &Self::Store) -> Option<usize>;
fn row_start(&self, store: &Self::Store) -> Option<usize>;
fn column_span(&self, store: &Self::Store) -> Option<usize>;
fn row_span(&self, store: &Self::Store) -> Option<usize>;
}
pub(crate) trait NodeExt: Node {
fn main(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
match parent_layout_type {
LayoutType::Row | LayoutType::Grid => self.width(store).unwrap_or(Units::Stretch(1.0)),
LayoutType::Column => self.height(store).unwrap_or(Units::Stretch(1.0)),
}
}
fn min_main(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(
store,
|store| self.min_width(store),
|store| self.min_height(store),
Units::Pixels(0.0),
)
}
fn max_main(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(
store,
|store| self.max_width(store),
|store| self.max_height(store),
Units::Pixels(f32::MAX),
)
}
fn cross(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
match parent_layout_type {
LayoutType::Row | LayoutType::Grid => self.height(store).unwrap_or(Units::Stretch(1.0)),
LayoutType::Column => self.width(store).unwrap_or(Units::Stretch(1.0)),
}
}
fn min_cross(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(
store,
|store| self.min_height(store),
|store| self.min_width(store),
Units::Pixels(0.0),
)
}
fn max_cross(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(
store,
|store| self.max_height(store),
|store| self.max_width(store),
Units::Pixels(f32::MAX),
)
}
fn main_before(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(store, |store| self.left(store), |store| self.top(store), Units::Auto)
}
fn main_after(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(
store,
|store| self.right(store),
|store| self.bottom(store),
Units::Auto,
)
}
fn cross_before(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(store, |store| self.top(store), |store| self.left(store), Units::Auto)
}
fn cross_after(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap_default(
store,
|store| self.bottom(store),
|store| self.right(store),
Units::Auto,
)
}
fn padding_main_before(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
if parent_layout_type == LayoutType::Row && self.direction(store).unwrap_or_default() == Direction::RightToLeft
{
self.padding_right(store).unwrap_or_default()
} else {
parent_layout_type.select_unwrap(store, |store| self.padding_left(store), |store| self.padding_top(store))
}
}
fn padding_main_after(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
if parent_layout_type == LayoutType::Row && self.direction(store).unwrap_or_default() == Direction::RightToLeft
{
self.padding_left(store).unwrap_or_default()
} else {
parent_layout_type.select_unwrap(
store,
|store| self.padding_right(store),
|store| self.padding_bottom(store),
)
}
}
fn padding_cross_before(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.padding_top(store), |store| self.padding_left(store))
}
fn padding_cross_after(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.padding_bottom(store), |store| self.padding_right(store))
}
fn main_between(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.horizontal_gap(store), |store| self.vertical_gap(store))
}
fn min_main_between(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(
store,
|store| self.min_horizontal_gap(store),
|store| self.min_vertical_gap(store),
)
}
fn max_main_between(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(
store,
|store| self.max_horizontal_gap(store),
|store| self.max_vertical_gap(store),
)
}
fn cross_between(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.vertical_gap(store), |store| self.horizontal_gap(store))
}
fn border_main_before(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.border_left(store), |store| self.border_top(store))
}
fn border_main_after(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.border_right(store), |store| self.border_bottom(store))
}
fn border_cross_before(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.border_top(store), |store| self.border_left(store))
}
fn border_cross_after(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Units {
parent_layout_type.select_unwrap(store, |store| self.border_bottom(store), |store| self.border_right(store))
}
fn content_sizing(
&self,
store: &Self::Store,
sublayout: &mut Self::SubLayout<'_>,
parent_layout_type: LayoutType,
parent_main: Option<f32>,
parent_cross: Option<f32>,
) -> Option<(f32, f32)> {
match parent_layout_type {
LayoutType::Row | LayoutType::Grid => self.content_size(store, sublayout, parent_main, parent_cross),
LayoutType::Column => {
self.content_size(store, sublayout, parent_cross, parent_main).map(|(width, height)| (height, width))
}
}
}
fn cross_scroll(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Option<f32> {
parent_layout_type.select(store, |store| self.vertical_scroll(store), |store| self.horizontal_scroll(store))
}
fn main_scroll(&self, store: &Self::Store, parent_layout_type: LayoutType) -> Option<f32> {
parent_layout_type.select(store, |store| self.horizontal_scroll(store), |store| self.vertical_scroll(store))
}
}
impl<N: Node> NodeExt for N {}