Skip to main content

lv_tui/widgets/
row.rs

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
9/// 水平排列容器 widget
10pub 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}