summaryrefslogtreecommitdiffstats
path: root/src/widget/row.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/widget/row.rs218
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)
+ }
+}