Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions core/src/layout/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ impl Node {
}

/// Translates the [`Node`] by the given translation.
pub fn translate(self, translation: impl Into<Vector>) -> Self {
let translation = translation.into();
pub fn translate(mut self, translation: impl Into<Vector>) -> Self {
self.translate_mut(translation);
self
}

Self {
bounds: self.bounds + translation,
..self
}
/// Translates the [`Node`] by the given translation.
pub fn translate_mut(&mut self, translation: impl Into<Vector>) {
self.bounds = self.bounds + translation.into();
}
}
7 changes: 4 additions & 3 deletions examples/layout/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,10 @@ fn application<'a>() -> Element<'a, Message> {
scrollable(
column![
"Content!",
square(400),
square(200),
square(400),
row((1..10).map(|i| square(if i % 2 == 0 { 80 } else { 160 })))
.spacing(20)
.align_y(Center)
.wrap(),
"The end"
]
.spacing(40)
Expand Down
200 changes: 200 additions & 0 deletions widget/src/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ where
) -> Self {
children.into_iter().fold(self, Self::push)
}

/// Turns the [`Row`] into a [`Wrapping`] row.
///
/// The original alignment of the [`Row`] is preserved per row wrapped.
pub fn wrap(self) -> Wrapping<'a, Message, Theme, Renderer> {
Wrapping { row: self }
}
}

impl<'a, Message, Renderer> Default for Row<'a, Message, Renderer>
Expand Down Expand Up @@ -339,3 +346,196 @@ where
Self::new(row)
}
}

/// A [`Row`] that wraps its contents.
///
/// Create a [`Row`] first, and then call [`Row::wrap`] to
/// obtain a [`Row`] that wraps its contents.
///
/// The original alignment of the [`Row`] is preserved per row wrapped.
#[allow(missing_debug_implementations)]
pub struct Wrapping<
'a,
Message,
Theme = crate::Theme,
Renderer = crate::Renderer,
> {
row: Row<'a, Message, Theme, Renderer>,
}

impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
for Wrapping<'a, Message, Theme, Renderer>
where
Renderer: crate::core::Renderer,
{
fn children(&self) -> Vec<Tree> {
self.row.children()
}

fn diff(&self, tree: &mut Tree) {
self.row.diff(tree);
}

fn size(&self) -> Size<Length> {
self.row.size()
}

fn layout(
&self,
tree: &mut Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
let limits = limits
.width(self.row.width)
.height(self.row.height)
.shrink(self.row.padding);

let spacing = self.row.spacing;
let max_width = limits.max().width;

let mut children: Vec<layout::Node> = Vec::new();
let mut intrinsic_size = Size::ZERO;
let mut row_start = 0;
let mut row_height = 0.0;
let mut x = 0.0;
let mut y = 0.0;

let align_factor = match self.row.align {
Alignment::Start => 0.0,
Alignment::Center => 2.0,
Alignment::End => 1.0,
};

let align = |row_start: std::ops::Range<usize>,
row_height: f32,
children: &mut Vec<layout::Node>| {
if align_factor != 0.0 {
for node in &mut children[row_start] {
let height = node.size().height;

node.translate_mut(Vector::new(
0.0,
(row_height - height) / align_factor,
));
}
}
};

for (i, child) in self.row.children.iter().enumerate() {
let node = child.as_widget().layout(
&mut tree.children[i],
renderer,
&limits,
);

let child_size = node.size();

if x != 0.0 && x + child_size.width > max_width {
intrinsic_size.width = intrinsic_size.width.max(x - spacing);

align(row_start..i, row_height, &mut children);

y += row_height + spacing;
x = 0.0;
row_start = i;
row_height = 0.0;
}

row_height = row_height.max(child_size.height);

children.push(node.move_to((
x + self.row.padding.left,
y + self.row.padding.top,
)));

x += child_size.width + spacing;
}

if x != 0.0 {
intrinsic_size.width = intrinsic_size.width.max(x - spacing);
}

intrinsic_size.height = (y - spacing).max(0.0) + row_height;
align(row_start..children.len(), row_height, &mut children);

let size =
limits.resolve(self.row.width, self.row.height, intrinsic_size);

layout::Node::with_children(size.expand(self.row.padding), children)
}

fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn Operation<()>,
) {
self.row.operate(tree, layout, renderer, operation);
}

fn on_event(
&mut self,
tree: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) -> event::Status {
self.row.on_event(
tree, event, layout, cursor, renderer, clipboard, shell, viewport,
)
}

fn mouse_interaction(
&self,
tree: &Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.row
.mouse_interaction(tree, layout, cursor, viewport, renderer)
}

fn draw(
&self,
tree: &Tree,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
self.row
.draw(tree, renderer, theme, style, layout, cursor, viewport);
}

fn overlay<'b>(
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
translation: Vector,
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
self.row.overlay(tree, layout, renderer, translation)
}
}

impl<'a, Message, Theme, Renderer> From<Wrapping<'a, Message, Theme, Renderer>>
for Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Theme: 'a,
Renderer: crate::core::Renderer + 'a,
{
fn from(row: Wrapping<'a, Message, Theme, Renderer>) -> Self {
Self::new(row)
}
}