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) {
82 return;
83 }
84 for child in &mut self.children {
85 let mut child_cx = EventCx::new(
86 &mut child.dirty,
87 cx.global_dirty,
88 cx.quit,
89 cx.phase,
90 cx.propagation_stopped,
91 );
92 child.component.event(event, &mut child_cx);
93 }
94 }
95
96 fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) {
97 let inner = rect.inner(self.style.padding);
98
99 let child_constraint = Constraint::loose(inner.width, inner.height);
100
101 let items: Vec<LayoutItem> = self
102 .children
103 .iter()
104 .map(|child| {
105 let s = child.component.style();
106 LayoutItem {
107 width: s.width,
108 height: match s.height {
109 Length::Auto => {
110 let measured = child.measure(child_constraint);
111 Length::Fixed(measured.height)
112 }
113 other => other,
114 },
115 margin: s.margin,
116 flex_grow: s.flex_grow,
117 flex_shrink: s.flex_shrink,
118 }
119 })
120 .collect();
121
122 let child_rects = layout_vertical(inner, &items, self.style.gap);
123
124 for (child, child_rect) in self.children.iter_mut().zip(child_rects.iter()) {
125 child.layout(*child_rect);
126 }
127 }
128
129 fn for_each_child(&self, f: &mut dyn FnMut(&Node)) {
130 for child in &self.children {
131 f(child);
132 }
133 }
134
135 fn for_each_child_mut(&mut self, f: &mut dyn FnMut(&mut Node)) {
136 for child in &mut self.children {
137 f(child);
138 }
139 }
140
141 fn style(&self) -> Style {
142 self.style.clone()
143 }
144}