use ratatui_core::layout::Rect;
use crate::geometry::{Padding, Size};
use crate::layout::{Align, AlignContent, FlexItemStyle, FlexWrap};
use crate::surface::Surface;
use crate::view::{Element, RenderCtx, ScopedElement, View};
use super::Flex;
pub struct Flow<V: View = Element> {
flex: Flex<V>,
}
impl<V: View> Flow<V> {
pub fn gap(mut self, gap: u16) -> Self {
self.flex = self.flex.gap(gap);
self
}
pub fn row_gap(mut self, gap: u16) -> Self {
self.flex = self.flex.row_gap(gap);
self
}
pub fn column_gap(mut self, gap: u16) -> Self {
self.flex = self.flex.column_gap(gap);
self
}
pub fn padding(mut self, padding: Padding) -> Self {
self.flex = self.flex.padding(padding);
self
}
pub fn align(mut self, align: Align) -> Self {
self.flex = self.flex.align(align);
self
}
pub fn align_content(mut self, align: AlignContent) -> Self {
self.flex = self.flex.align_content(align);
self
}
pub fn item(mut self, view: V) -> Self {
self.flex = self.flex.auto(view);
self
}
pub fn fixed(mut self, width: u16, view: V) -> Self {
self.flex = self.flex.fixed(width, view);
self
}
pub fn styled(mut self, style: FlexItemStyle, view: V) -> Self {
self.flex = self.flex.styled(style, view);
self
}
pub fn solve(&self, area: Rect, ctx: &RenderCtx) -> Vec<Rect> {
self.flex.solve(area, ctx)
}
}
impl Flow<Element> {
pub fn new() -> Self {
Self {
flex: Flex::row()
.wrap(FlexWrap::Wrap)
.align(Align::Start)
.align_content(AlignContent::Start),
}
}
pub fn scoped<'view>() -> Flow<ScopedElement<'view>> {
Flow {
flex: Flex::scoped_row()
.wrap(FlexWrap::Wrap)
.align(Align::Start)
.align_content(AlignContent::Start),
}
}
}
impl Default for Flow<Element> {
fn default() -> Self {
Self::new()
}
}
impl<V: View> View for Flow<V> {
fn measure(&self, available: Size, ctx: &RenderCtx) -> Size {
self.flex.measure(available, ctx)
}
fn render(&self, area: Rect, surface: &mut Surface, ctx: &RenderCtx) {
self.flex.render(area, surface, ctx);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::components::Text;
#[test]
fn flow_wraps_intrinsic_items() {
let flow = Flow::new()
.column_gap(1)
.row_gap(1)
.item(crate::element(Text::raw("one")))
.item(crate::element(Text::raw("two")))
.item(crate::element(Text::raw("three")));
let theme = crate::Theme::default();
let rects = flow.solve(Rect::new(0, 0, 7, 5), &RenderCtx::new(&theme));
assert_eq!(rects[0], Rect::new(0, 0, 3, 1));
assert_eq!(rects[1], Rect::new(4, 0, 3, 1));
assert_eq!(rects[2], Rect::new(0, 2, 5, 1));
}
}