iced_native/widget/
row.rs

1//! Distribute content horizontally.
2use crate::event::{self, Event};
3use crate::layout::{self, Layout};
4use crate::mouse;
5use crate::overlay;
6use crate::renderer;
7use crate::widget::{Operation, Tree};
8use crate::{
9    Alignment, Clipboard, Element, Length, Padding, Pixels, Point, Rectangle,
10    Shell, Widget,
11};
12
13/// A container that distributes its contents horizontally.
14#[allow(missing_debug_implementations)]
15pub struct Row<'a, Message, Renderer> {
16    spacing: f32,
17    padding: Padding,
18    width: Length,
19    height: Length,
20    align_items: Alignment,
21    children: Vec<Element<'a, Message, Renderer>>,
22}
23
24impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
25    /// Creates an empty [`Row`].
26    pub fn new() -> Self {
27        Self::with_children(Vec::new())
28    }
29
30    /// Creates a [`Row`] with the given elements.
31    pub fn with_children(
32        children: Vec<Element<'a, Message, Renderer>>,
33    ) -> Self {
34        Row {
35            spacing: 0.0,
36            padding: Padding::ZERO,
37            width: Length::Shrink,
38            height: Length::Shrink,
39            align_items: Alignment::Start,
40            children,
41        }
42    }
43
44    /// Sets the horizontal spacing _between_ elements.
45    ///
46    /// Custom margins per element do not exist in iced. You should use this
47    /// method instead! While less flexible, it helps you keep spacing between
48    /// elements consistent.
49    pub fn spacing(mut self, amount: impl Into<Pixels>) -> Self {
50        self.spacing = amount.into().0;
51        self
52    }
53
54    /// Sets the [`Padding`] of the [`Row`].
55    pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
56        self.padding = padding.into();
57        self
58    }
59
60    /// Sets the width of the [`Row`].
61    pub fn width(mut self, width: impl Into<Length>) -> Self {
62        self.width = width.into();
63        self
64    }
65
66    /// Sets the height of the [`Row`].
67    pub fn height(mut self, height: impl Into<Length>) -> Self {
68        self.height = height.into();
69        self
70    }
71
72    /// Sets the vertical alignment of the contents of the [`Row`] .
73    pub fn align_items(mut self, align: Alignment) -> Self {
74        self.align_items = align;
75        self
76    }
77
78    /// Adds an [`Element`] to the [`Row`].
79    pub fn push(
80        mut self,
81        child: impl Into<Element<'a, Message, Renderer>>,
82    ) -> Self {
83        self.children.push(child.into());
84        self
85    }
86}
87
88impl<'a, Message, Renderer> Default for Row<'a, Message, Renderer> {
89    fn default() -> Self {
90        Self::new()
91    }
92}
93
94impl<'a, Message, Renderer> Widget<Message, Renderer>
95    for Row<'a, Message, Renderer>
96where
97    Renderer: crate::Renderer,
98{
99    fn children(&self) -> Vec<Tree> {
100        self.children.iter().map(Tree::new).collect()
101    }
102
103    fn diff(&self, tree: &mut Tree) {
104        tree.diff_children(&self.children)
105    }
106
107    fn width(&self) -> Length {
108        self.width
109    }
110
111    fn height(&self) -> Length {
112        self.height
113    }
114
115    fn layout(
116        &self,
117        renderer: &Renderer,
118        limits: &layout::Limits,
119    ) -> layout::Node {
120        let limits = limits.width(self.width).height(self.height);
121
122        layout::flex::resolve(
123            layout::flex::Axis::Horizontal,
124            renderer,
125            &limits,
126            self.padding,
127            self.spacing,
128            self.align_items,
129            &self.children,
130        )
131    }
132
133    fn operate(
134        &self,
135        tree: &mut Tree,
136        layout: Layout<'_>,
137        renderer: &Renderer,
138        operation: &mut dyn Operation<Message>,
139    ) {
140        operation.container(None, &mut |operation| {
141            self.children
142                .iter()
143                .zip(&mut tree.children)
144                .zip(layout.children())
145                .for_each(|((child, state), layout)| {
146                    child
147                        .as_widget()
148                        .operate(state, layout, renderer, operation);
149                })
150        });
151    }
152
153    fn on_event(
154        &mut self,
155        tree: &mut Tree,
156        event: Event,
157        layout: Layout<'_>,
158        cursor_position: Point,
159        renderer: &Renderer,
160        clipboard: &mut dyn Clipboard,
161        shell: &mut Shell<'_, Message>,
162    ) -> event::Status {
163        self.children
164            .iter_mut()
165            .zip(&mut tree.children)
166            .zip(layout.children())
167            .map(|((child, state), layout)| {
168                child.as_widget_mut().on_event(
169                    state,
170                    event.clone(),
171                    layout,
172                    cursor_position,
173                    renderer,
174                    clipboard,
175                    shell,
176                )
177            })
178            .fold(event::Status::Ignored, event::Status::merge)
179    }
180
181    fn mouse_interaction(
182        &self,
183        tree: &Tree,
184        layout: Layout<'_>,
185        cursor_position: Point,
186        viewport: &Rectangle,
187        renderer: &Renderer,
188    ) -> mouse::Interaction {
189        self.children
190            .iter()
191            .zip(&tree.children)
192            .zip(layout.children())
193            .map(|((child, state), layout)| {
194                child.as_widget().mouse_interaction(
195                    state,
196                    layout,
197                    cursor_position,
198                    viewport,
199                    renderer,
200                )
201            })
202            .max()
203            .unwrap_or_default()
204    }
205
206    fn draw(
207        &self,
208        tree: &Tree,
209        renderer: &mut Renderer,
210        theme: &Renderer::Theme,
211        style: &renderer::Style,
212        layout: Layout<'_>,
213        cursor_position: Point,
214        viewport: &Rectangle,
215    ) {
216        for ((child, state), layout) in self
217            .children
218            .iter()
219            .zip(&tree.children)
220            .zip(layout.children())
221        {
222            child.as_widget().draw(
223                state,
224                renderer,
225                theme,
226                style,
227                layout,
228                cursor_position,
229                viewport,
230            );
231        }
232    }
233
234    fn overlay<'b>(
235        &'b mut self,
236        tree: &'b mut Tree,
237        layout: Layout<'_>,
238        renderer: &Renderer,
239    ) -> Option<overlay::Element<'b, Message, Renderer>> {
240        overlay::from_children(&mut self.children, tree, layout, renderer)
241    }
242}
243
244impl<'a, Message, Renderer> From<Row<'a, Message, Renderer>>
245    for Element<'a, Message, Renderer>
246where
247    Message: 'a,
248    Renderer: crate::Renderer + 'a,
249{
250    fn from(row: Row<'a, Message, Renderer>) -> Self {
251        Self::new(row)
252    }
253}