pixel_widgets/widget/
row.rs

1use crate::draw::Primitive;
2use crate::event::Event;
3use crate::layout::{Rectangle, Size};
4use crate::node::{GenericNode, IntoNode, Node};
5use crate::style::Stylesheet;
6use crate::widget::Context;
7
8use super::Widget;
9
10/// Layout child widgets horizontally
11pub struct Row<'a, T> {
12    children: Vec<Node<'a, T>>,
13    layout: Vec<Rectangle>,
14}
15
16impl<'a, T: 'a> Row<'a, T> {
17    /// Construct a new `Row`
18    pub fn new() -> Self {
19        Default::default()
20    }
21
22    /// Adds a child widget to the row
23    pub fn push<I: IntoNode<'a, T> + 'a>(mut self, item: I) -> Self {
24        self.children.push(item.into_node());
25        self
26    }
27
28    /// Adds child widgets using an iterator
29    pub fn extend<I: IntoIterator<Item = N>, N: IntoNode<'a, T> + 'a>(mut self, iter: I) -> Self {
30        self.children.extend(iter.into_iter().map(IntoNode::into_node));
31        self
32    }
33
34    fn layout(&mut self, layout: Rectangle, style: &Stylesheet) -> impl Iterator<Item = (&mut Node<'a, T>, Rectangle)> {
35        let layout = style.background.content_rect(layout, style.padding);
36        if self.layout.len() != self.children.len() {
37            let align = style.align_vertical;
38            let available_parts = self.children.iter().map(|c| c.size().0.parts()).sum();
39            let available_space = layout.width() - self.children.iter().map(|c| c.size().0.min_size()).sum::<f32>();
40            let mut cursor = 0.0;
41            self.layout = self
42                .children
43                .iter()
44                .map(|child| {
45                    let (w, h) = child.size();
46                    let w = w.resolve(available_space, available_parts).min(layout.width() - cursor);
47                    let h = h.resolve(layout.height(), h.parts());
48                    let x = cursor;
49                    let y = align.resolve_start(h, layout.height());
50
51                    cursor += w;
52                    Rectangle::from_xywh(x, y, w, h)
53                })
54                .collect();
55        }
56        self.children.iter_mut().zip(
57            self.layout
58                .iter()
59                .map(move |relative| relative.translate(layout.left, layout.top)),
60        )
61    }
62}
63
64impl<'a, T: 'a> Default for Row<'a, T> {
65    fn default() -> Self {
66        Self {
67            children: Vec::new(),
68            layout: Vec::new(),
69        }
70    }
71}
72
73impl<'a, T: 'a> Widget<'a, T> for Row<'a, T> {
74    type State = ();
75
76    fn mount(&self) {}
77
78    fn widget(&self) -> &'static str {
79        "row"
80    }
81
82    fn visit_children(&mut self, visitor: &mut dyn FnMut(&mut dyn GenericNode<'a, T>)) {
83        self.children.iter_mut().for_each(|child| visitor(&mut **child));
84    }
85
86    fn len(&self) -> usize {
87        self.children.len()
88    }
89
90    fn size(&self, _: &(), style: &Stylesheet) -> (Size, Size) {
91        let width = match style.width {
92            Size::Shrink => Size::Exact(self.children.iter().fold(0.0, |size, child| match child.size().0 {
93                Size::Exact(child_size) => size + child_size,
94                _ => size,
95            })),
96            other => other,
97        };
98        let height = match style.height {
99            Size::Shrink => Size::Exact(self.children.iter().fold(0.0, |size, child| match child.size().1 {
100                Size::Exact(child_size) => size.max(child_size),
101                _ => size,
102            })),
103            other => other,
104        };
105        style
106            .background
107            .resolve_size((style.width, style.height), (width, height), style.padding)
108    }
109
110    fn focused(&self, _: &()) -> bool {
111        self.children.iter().any(|child| child.focused())
112    }
113
114    fn event(
115        &mut self,
116        _: &mut (),
117        layout: Rectangle,
118        clip: Rectangle,
119        stylesheet: &Stylesheet,
120        event: Event,
121        context: &mut Context<T>,
122    ) {
123        let focused = self.children.iter().position(|child| child.focused());
124
125        for (index, (child, layout)) in self.layout(layout, stylesheet).enumerate() {
126            if Some(index) == focused {
127                child.event(layout, clip, event, context);
128            } else if focused.is_none() {
129                if let Some(clip) = clip.intersect(&layout) {
130                    child.event(layout, clip, event, context);
131                }
132            }
133        }
134    }
135
136    fn draw(&mut self, _: &mut (), layout: Rectangle, clip: Rectangle, stylesheet: &Stylesheet) -> Vec<Primitive<'a>> {
137        let mut result = Vec::new();
138
139        result.extend(stylesheet.background.render(layout));
140
141        result = self
142            .layout(layout, stylesheet)
143            .fold(result, |mut result, (child, layout)| {
144                result.extend(child.draw(layout, clip));
145                result
146            });
147
148        result
149    }
150}
151
152impl<'a, T: 'a> IntoNode<'a, T> for Row<'a, T> {
153    fn into_node(self) -> Node<'a, T> {
154        Node::from_widget(self)
155    }
156}