Skip to content

Commit

Permalink
Add LinearLayout::arrange_view_group
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Oct 10, 2023
1 parent bcd638a commit 490cbf4
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 20 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
61 changes: 46 additions & 15 deletions src/layout/linear/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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<C, LD, VG> Drawable for LinearLayout<LD, VG>
Expand Down
16 changes: 13 additions & 3 deletions src/view_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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
Expand Down
36 changes: 34 additions & 2 deletions src/view_group/object_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<V> ViewGroup for Chain<V>
Expand All @@ -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)
}
}
10 changes: 10 additions & 0 deletions src/view_group/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> View for Views<'_, T>
Expand Down

0 comments on commit 490cbf4

Please sign in to comment.