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