use crate::component::{Component, EventCx, LayoutCx, MeasureCx};
use crate::event::Event;
use crate::geom::{Rect, Size};
use crate::layout::{layout_vertical, Constraint, LayoutItem};
use crate::node::Node;
use crate::render::RenderCx;
use crate::style::{Layout, Length, Style};
pub struct Column {
children: Vec<Node>,
style: Style,
}
impl Column {
pub fn new() -> Self {
Self {
children: Vec::new(),
style: Style::default().layout(Layout::Vertical),
}
}
pub fn child(mut self, component: impl Component + 'static) -> Self {
self.children.push(Node::new(component));
self
}
pub fn padding(mut self, value: u16) -> Self {
self.style = self.style.padding(value);
self
}
pub fn gap(mut self, value: u16) -> Self {
self.style = self.style.gap(value);
self
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
}
impl Component for Column {
fn render(&self, cx: &mut RenderCx) {
for child in &self.children {
child.render_with_parent(cx.buffer, cx.focused_id, cx.clip_rect, cx.wrap, cx.truncate, cx.align, Some(&cx.style));
}
}
fn measure(&self, constraint: Constraint, _cx: &mut MeasureCx) -> Size {
let mut height = self.style.padding.top + self.style.padding.bottom;
let mut max_width: u16 = 0;
for (i, child) in self.children.iter().enumerate() {
let child_size = child.measure(constraint);
height = height.saturating_add(child_size.height);
max_width = max_width.max(child_size.width);
if i < self.children.len().saturating_sub(1) {
height = height.saturating_add(self.style.gap);
}
}
let width = max_width
.saturating_add(self.style.padding.left)
.saturating_add(self.style.padding.right)
.min(constraint.max.width);
Size { width, height }
}
fn focusable(&self) -> bool {
false
}
fn event(&mut self, event: &Event, cx: &mut EventCx) {
if matches!(event, Event::Focus | Event::Blur | Event::Tick) {
return;
}
for child in &mut self.children {
let mut child_cx = EventCx::new(
&mut child.dirty,
cx.global_dirty,
cx.quit,
cx.phase,
cx.propagation_stopped,
);
child.component.event(event, &mut child_cx);
}
}
fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) {
let inner = rect.inner(self.style.padding);
let child_constraint = Constraint::loose(inner.width, inner.height);
let items: Vec<LayoutItem> = self
.children
.iter()
.map(|child| {
let s = child.component.style();
LayoutItem {
width: s.width,
height: match s.height {
Length::Auto => {
let measured = child.measure(child_constraint);
Length::Fixed(measured.height)
}
other => other,
},
margin: s.margin,
flex_grow: s.flex_grow,
flex_shrink: s.flex_shrink,
}
})
.collect();
let child_rects = layout_vertical(inner, &items, self.style.gap);
for (child, child_rect) in self.children.iter_mut().zip(child_rects.iter()) {
child.layout(*child_rect);
}
}
fn for_each_child(&self, f: &mut dyn FnMut(&Node)) {
for child in &self.children {
f(child);
}
}
fn for_each_child_mut(&mut self, f: &mut dyn FnMut(&mut Node)) {
for child in &mut self.children {
f(child);
}
}
fn style(&self) -> Style {
self.style.clone()
}
}