diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ea580..ce06603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ * `LinearLayout` now implements `ViewGroup` * `LinearLayout::inner{_mut}` +* `LinearLayout::arrange_view_group` * `Orientation::compute_offset` +* `ViewGroup::bounds_of` +* `ViewGroup::translate_child` ## Changed diff --git a/src/layout/linear/mod.rs b/src/layout/linear/mod.rs index 7558d79..9527213 100644 --- a/src/layout/linear/mod.rs +++ b/src/layout/linear/mod.rs @@ -72,9 +72,10 @@ //! [`horizontal::Left`]: crate::align::horizontal::Left use crate::{ + align::{horizontal, vertical}, align::{HorizontalAlignment, VerticalAlignment}, - prelude::*, - view_group::ViewGroup, + view_group::{EmptyViewGroup, ViewGroup}, + View, }; mod orientation; @@ -300,30 +301,47 @@ where } /// Arrange the views according to the layout properties and return the views as a [`ViewGroup`]. - /// Note: The top left point is always `Point::zero()`. - /// - /// [`View::translate`]: crate::View::translate - /// [`Align`]: crate::align::Align #[inline] + #[must_use] pub fn arrange(mut self) -> Self { - let view_count = self.views.len(); + // Place first child to the layout's position. + self.views + .translate_child(0, self.position - self.views.bounds_of(0).top_left); + + // We can't use `self` because we borrow parts of it mutably. + LinearLayout { + position: Point::zero(), + direction: self.direction, + views: EmptyViewGroup, + } + .arrange_view_group(&mut self.views); + + self + } + + /// Arrange a [`ViewGroup`] according to the layout properties. + #[inline] + pub fn arrange_view_group(&self, view_group: &mut impl ViewGroup) { + let view_count = view_group.len(); // measure - let mut size = self.views.at(0).size(); + let bounds = view_group.bounds_of(0); + let position = bounds.top_left; + let mut size = bounds.size(); for i in 1..view_count { - let current_el_size = self.views.at(i).size(); + let current_el_size = view_group.bounds_of(i).size(); size = LD::Secondary::measure(size, current_el_size); } // arrange - let mut bounds = Rectangle::new(self.position, size); + let mut bounds = Rectangle::new(position, size); for i in 0..view_count { - bounds = self - .direction - .place(self.views.at_mut(i), size, bounds, i, view_count); + let offset = + self.direction + .compute_offset(view_group.bounds_of(i), size, bounds, i, view_count); + view_group.translate_child(i, offset); + bounds = view_group.bounds_of(i); } - - self } } @@ -353,17 +371,30 @@ where LD: Orientation, VG: ViewGroup, { + #[inline] fn len(&self) -> usize { self.views.len() } + #[inline] fn at(&self, idx: usize) -> &dyn View { self.views.at(idx) } + #[inline] fn at_mut(&mut self, idx: usize) -> &mut dyn View { self.views.at_mut(idx) } + + #[inline] + fn bounds_of(&self, idx: usize) -> Rectangle { + self.views.bounds_of(idx) + } + + #[inline] + fn translate_child(&mut self, idx: usize, by: Point) { + self.views.translate_child(idx, by) + } } impl Drawable for LinearLayout diff --git a/src/view_group/mod.rs b/src/view_group/mod.rs index dff3c36..4a8d746 100644 --- a/src/view_group/mod.rs +++ b/src/view_group/mod.rs @@ -19,6 +19,16 @@ pub trait ViewGroup: View { /// Returns an exclusive reference to the [`View`] object at position `idx`. fn at_mut(&mut self, idx: usize) -> &mut dyn View; + + /// Returns the bounding box of the given View. + fn bounds_of(&self, idx: usize) -> Rectangle { + self.at(idx).bounds() + } + + /// Translates the given View. + fn translate_child(&mut self, idx: usize, by: Point) { + self.at_mut(idx).translate_impl(by) + } } /// A [`ViewGroup`] that contains no [`View`] objects. @@ -58,7 +68,7 @@ impl ViewGroupHelper { #[inline] pub fn translate(vg: &mut impl ViewGroup, by: Point) { for i in 0..ViewGroup::len(vg) { - vg.at_mut(i).translate_impl(by); + vg.translate_child(i, by); } } @@ -69,10 +79,10 @@ impl ViewGroupHelper { return EmptyViewGroup.bounds(); } - let mut rect = vg.at(0).bounds(); + let mut rect = vg.bounds_of(0); for i in 1..vg.len() { - rect = rect.enveloping(&vg.at(i).bounds()); + rect = rect.enveloping(&vg.bounds_of(i)); } rect diff --git a/src/view_group/object_chain.rs b/src/view_group/object_chain.rs index 4970cf4..7b00a0a 100644 --- a/src/view_group/object_chain.rs +++ b/src/view_group/object_chain.rs @@ -112,6 +112,24 @@ where self.parent.at_mut(index) } + + #[inline] + fn bounds_of(&self, index: usize) -> Rectangle { + if index == ViewGroup::len(self) - 1 { + return self.object.bounds(); + } + + self.parent.bounds_of(index) + } + + #[inline] + fn translate_child(&mut self, index: usize, by: Point) { + if index == ViewGroup::len(self) - 1 { + return self.object.translate_impl(by); + } + + self.parent.translate_child(index, by) + } } impl ViewGroup for Chain @@ -125,15 +143,29 @@ where #[inline] fn at(&self, index: usize) -> &dyn View { - assert!(index == 0); + assert_eq!(index, 0); &self.object } #[inline] fn at_mut(&mut self, index: usize) -> &mut dyn View { - assert!(index == 0); + assert_eq!(index, 0); &mut self.object } + + #[inline] + fn bounds_of(&self, index: usize) -> Rectangle { + assert_eq!(index, 0); + + self.object.bounds() + } + + #[inline] + fn translate_child(&mut self, index: usize, by: Point) { + assert_eq!(index, 0); + + self.object.translate_impl(by) + } } diff --git a/src/view_group/views.rs b/src/view_group/views.rs index 6a7abb6..65b841b 100644 --- a/src/view_group/views.rs +++ b/src/view_group/views.rs @@ -47,6 +47,16 @@ where fn at_mut(&mut self, idx: usize) -> &mut dyn View { &mut self.views[idx] } + + #[inline] + fn bounds_of(&self, idx: usize) -> Rectangle { + self.views[idx].bounds() + } + + #[inline] + fn translate_child(&mut self, idx: usize, by: Point) { + self.views[idx].translate_impl(by) + } } impl View for Views<'_, T>