1use crate::component::{Component, EventCx, LayoutCx, MeasureCx};
2use crate::event::Event;
3use crate::geom::{Rect, Size};
4use crate::layout::{layout_vertical, Constraint, LayoutItem};
5use crate::node::Node;
6use crate::render::RenderCx;
7use crate::style::{Layout, Length, Style};
8
9pub struct Column {
14 children: Vec<Node>,
15 style: Style,
16}
17
18impl Column {
19 pub fn new() -> Self {
21 Self {
22 children: Vec::new(),
23 style: Style::default().layout(Layout::Vertical),
24 }
25 }
26
27 pub fn child(mut self, component: impl Component + 'static) -> Self {
28 self.children.push(Node::new(component));
29 self
30 }
31
32 pub fn padding(mut self, value: u16) -> Self {
33 self.style = self.style.padding(value);
34 self
35 }
36
37 pub fn gap(mut self, value: u16) -> Self {
38 self.style = self.style.gap(value);
39 self
40 }
41
42 pub fn style(mut self, style: Style) -> Self {
43 self.style = style;
44 self
45 }
46}
47
48impl Component for Column {
49 fn render(&self, cx: &mut RenderCx) {
50 for child in &self.children {
51 child.render_with_parent(cx.buffer, cx.focused_id, cx.clip_rect, cx.wrap, cx.truncate, cx.align, Some(&cx.style));
52 }
53 }
54
55 fn measure(&self, constraint: Constraint, _cx: &mut MeasureCx) -> Size {
56 let mut height = self.style.padding.top + self.style.padding.bottom;
57 let mut max_width: u16 = 0;
58
59 for (i, child) in self.children.iter().enumerate() {
60 let child_size = child.measure(constraint);
61 height = height.saturating_add(child_size.height);
62 max_width = max_width.max(child_size.width);
63 if i < self.children.len().saturating_sub(1) {
64 height = height.saturating_add(self.style.gap);
65 }
66 }
67
68 let width = max_width
69 .saturating_add(self.style.padding.left)
70 .saturating_add(self.style.padding.right)
71 .min(constraint.max.width);
72
73 Size { width, height }
74 }
75
76 fn focusable(&self) -> bool {
77 false
78 }
79
80 fn event(&mut self, event: &Event, cx: &mut EventCx) {
81 if matches!(event, Event::Focus | Event::Blur | Event::Tick) { return; }
82 for child in &mut self.children {
83 let mut child_cx = EventCx::new(
84 &mut child.dirty,
85 cx.global_dirty,
86 cx.quit,
87 cx.phase,
88 cx.propagation_stopped,
89 );
90 child.component.event(event, &mut child_cx);
91 }
92 }
93
94 fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) {
95 let inner = rect.inner(self.style.padding);
96
97 let child_constraint = Constraint::loose(inner.width, inner.height);
98
99 let items: Vec<LayoutItem> = self
100 .children
101 .iter()
102 .map(|child| {
103 let s = child.component.style();
104 LayoutItem {
105 width: s.width,
106 height: match s.height {
107 Length::Auto => {
108 let measured = child.measure(child_constraint);
109 Length::Fixed(measured.height)
110 }
111 other => other,
112 },
113 margin: s.margin,
114 flex_grow: s.flex_grow,
115 flex_shrink: s.flex_shrink,
116 }
117 })
118 .collect();
119
120 let child_rects = layout_vertical(inner, &items, self.style.gap);
121
122 for (child, child_rect) in self.children.iter_mut().zip(child_rects.iter()) {
123 child.layout(*child_rect);
124 }
125 }
126
127 fn for_each_child(&self, f: &mut dyn FnMut(&Node)) {
128 for child in &self.children {
129 f(child);
130 }
131 }
132
133 fn for_each_child_mut(&mut self, f: &mut dyn FnMut(&mut Node)) {
134 for child in &mut self.children {
135 f(child);
136 }
137 }
138
139 fn style(&self) -> Style {
140 self.style.clone()
141 }
142}