mod layout;
mod node;
mod reconcile;
pub(crate) use self::layout::{measure_flow, pack_rows};
pub use self::node::FlowNode;
pub(crate) use self::reconcile::reconcile_flow;
use crate::core::element::{Element, ElementKind};
use crate::style::{Align, BorderStyle, LayoutConstraints, Length, Padding, ShrinkPriority, Style};
#[derive(Clone)]
pub struct Flow {
pub(crate) children: Vec<Element>,
pub(crate) gap: u16,
pub(crate) row_gap: Option<u16>,
pub(crate) align: Align,
pub(crate) padding: Padding,
pub(crate) border: bool,
pub(crate) border_style: BorderStyle,
pub(crate) style: Style,
pub(crate) width: Length,
pub(crate) height: Length,
pub(crate) shrinkable: bool,
}
impl Default for Flow {
fn default() -> Self {
Self {
children: Vec::new(),
gap: 0,
row_gap: None,
align: Align::Start,
padding: Padding::default(),
border: false,
border_style: BorderStyle::Plain,
style: Style::default(),
width: Length::Flex(1),
height: Length::Auto,
shrinkable: false,
}
}
}
impl Flow {
pub fn new() -> Self {
Self::default()
}
pub fn child(mut self, child: impl Into<Element>) -> Self {
self.children.push(child.into());
self
}
pub fn children(mut self, children: impl IntoIterator<Item = Element>) -> Self {
self.children = children.into_iter().collect();
self
}
pub fn gap(mut self, gap: u16) -> Self {
self.gap = gap;
self
}
pub fn row_gap(mut self, row_gap: u16) -> Self {
self.row_gap = Some(row_gap);
self
}
pub fn shrinkable(mut self, shrinkable: bool) -> Self {
self.shrinkable = shrinkable;
self
}
pub fn align(mut self, align: Align) -> Self {
self.align = align;
self
}
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
self.padding = padding.into();
self
}
pub fn border(mut self, border: bool) -> Self {
self.border = border;
self
}
pub fn border_style(mut self, border_style: BorderStyle) -> Self {
self.border_style = border_style;
self
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
}
}
impl From<Flow> for Element {
fn from(value: Flow) -> Self {
let shrink_priority = if value.shrinkable {
ShrinkPriority::First
} else {
ShrinkPriority::Normal
};
Element::new(ElementKind::Flow(value)).with_layout(
LayoutConstraints::default()
.reflows(true)
.shrink_priority(shrink_priority),
)
}
}
impl crate::layout::hash::LayoutHash for Flow {
fn layout_hash(
&self,
hasher: &mut impl std::hash::Hasher,
recurse: &dyn Fn(&Element) -> Option<u64>,
) -> Option<()> {
use std::hash::Hash;
self.gap.hash(hasher);
self.row_gap.hash(hasher);
self.align.hash(hasher);
self.padding.hash(hasher);
self.border.hash(hasher);
self.border_style.hash(hasher);
self.width.hash(hasher);
self.height.hash(hasher);
self.shrinkable.hash(hasher);
let non_portal_count = self
.children
.iter()
.filter(|child| !matches!(child.kind, ElementKind::Portal(_)))
.count();
non_portal_count.hash(hasher);
for child in &self.children {
if matches!(child.kind, ElementKind::Portal(_)) {
continue;
}
recurse(child)?.hash(hasher);
}
Some(())
}
}