diff options
Diffstat (limited to '')
-rw-r--r-- | src/widget/row.rs | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/widget/row.rs b/src/widget/row.rs new file mode 100644 index 00000000..9e0f9d4c --- /dev/null +++ b/src/widget/row.rs @@ -0,0 +1,218 @@ +use std::hash::Hash; + +use crate::{ + Align, Element, Event, Hasher, Justify, Layout, MouseCursor, Node, Point, + Style, Widget, +}; + +/// A container that places its contents horizontally. +/// +/// A [`Row`] will try to fill the horizontal space of its container. +/// +/// [`Row`]: struct.Row.html +pub struct Row<'a, Message, Renderer> { + style: Style, + spacing: u16, + children: Vec<Element<'a, Message, Renderer>>, +} + +impl<'a, Message, Renderer> std::fmt::Debug for Row<'a, Message, Renderer> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Row") + .field("style", &self.style) + .field("spacing", &self.spacing) + .field("children", &self.children) + .finish() + } +} + +impl<'a, Message, Renderer> Row<'a, Message, Renderer> { + /// Creates an empty [`Row`]. + /// + /// [`Row`]: struct.Row.html + pub fn new() -> Self { + Row { + style: Style::default().fill_width(), + spacing: 0, + children: Vec::new(), + } + } + + /// Sets the horizontal spacing _between_ elements in pixels. + /// + /// Custom margins per element do not exist in Coffee. You should use this + /// method instead! While less flexible, it helps you keep spacing between + /// elements consistent. + pub fn spacing(mut self, px: u16) -> Self { + self.spacing = px; + self + } + + /// Sets the padding of the [`Row`] in pixels. + /// + /// [`Row`]: struct.Row.html + pub fn padding(mut self, px: u32) -> Self { + self.style = self.style.padding(px); + self + } + + /// Sets the width of the [`Row`] in pixels. + /// + /// [`Row`]: struct.Row.html + pub fn width(mut self, width: u32) -> Self { + self.style = self.style.width(width); + self + } + + /// Sets the height of the [`Row`] in pixels. + /// + /// [`Row`]: struct.Row.html + pub fn height(mut self, height: u32) -> Self { + self.style = self.style.height(height); + self + } + + /// Sets the maximum width of the [`Row`] in pixels. + /// + /// [`Row`]: struct.Row.html + pub fn max_width(mut self, max_width: u32) -> Self { + self.style = self.style.max_width(max_width); + self + } + + /// Sets the maximum height of the [`Row`] in pixels. + /// + /// [`Row`]: struct.Row.html + pub fn max_height(mut self, max_height: u32) -> Self { + self.style = self.style.max_height(max_height); + self + } + + /// Sets the alignment of the [`Row`] itself. + /// + /// This is useful if you want to override the default alignment given by + /// the parent container. + /// + /// [`Row`]: struct.Row.html + pub fn align_self(mut self, align: Align) -> Self { + self.style = self.style.align_self(align); + self + } + + /// Sets the vertical alignment of the contents of the [`Row`] . + /// + /// [`Row`]: struct.Row.html + pub fn align_items(mut self, align: Align) -> Self { + self.style = self.style.align_items(align); + self + } + + /// Sets the horizontal distribution strategy for the contents of the + /// [`Row`] . + /// + /// [`Row`]: struct.Row.html + pub fn justify_content(mut self, justify: Justify) -> Self { + self.style = self.style.justify_content(justify); + self + } + + /// Adds an [`Element`] to the [`Row`]. + /// + /// [`Element`]: ../core/struct.Element.html + /// [`Row`]: struct.Row.html + pub fn push<E>(mut self, child: E) -> Row<'a, Message, Renderer> + where + E: Into<Element<'a, Message, Renderer>>, + { + self.children.push(child.into()); + self + } +} + +impl<'a, Message, Renderer> Widget<Message, Renderer> + for Row<'a, Message, Renderer> +{ + fn node(&self, renderer: &Renderer) -> Node { + let mut children: Vec<Node> = self + .children + .iter() + .map(|child| { + let mut node = child.widget.node(renderer); + + let mut style = node.0.style(); + style.margin.end = + stretch::style::Dimension::Points(self.spacing as f32); + + node.0.set_style(style); + node + }) + .collect(); + + if let Some(node) = children.last_mut() { + let mut style = node.0.style(); + style.margin.end = stretch::style::Dimension::Undefined; + + node.0.set_style(style); + } + + Node::with_children(self.style, children) + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec<Message>, + ) { + self.children.iter_mut().zip(layout.children()).for_each( + |(child, layout)| { + child + .widget + .on_event(event, layout, cursor_position, messages) + }, + ); + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + cursor_position: Point, + ) -> MouseCursor { + let mut cursor = MouseCursor::OutOfBounds; + + self.children.iter().zip(layout.children()).for_each( + |(child, layout)| { + let new_cursor = + child.widget.draw(renderer, layout, cursor_position); + + if new_cursor != MouseCursor::OutOfBounds { + cursor = new_cursor; + } + }, + ); + + cursor + } + + fn hash(&self, state: &mut Hasher) { + self.style.hash(state); + self.spacing.hash(state); + + for child in &self.children { + child.widget.hash(state); + } + } +} + +impl<'a, Message, Renderer> From<Row<'a, Message, Renderer>> + for Element<'a, Message, Renderer> +where + Renderer: 'a, + Message: 'static, +{ + fn from(row: Row<'a, Message, Renderer>) -> Element<'a, Message, Renderer> { + Element::new(row) + } +} |