LinearLayout: use ChildIterator everywhere

For a more consistent sizing.
This commit is contained in:
Alexandre Bury 2017-11-06 23:51:44 -08:00
parent 11ea8a592b
commit dc75cdd115

View File

@ -40,20 +40,56 @@ impl Child {
} }
struct ChildIterator<I> { struct ChildIterator<I> {
// Actual iterator on the children
inner: I, inner: I,
// Current offset
offset: usize, offset: usize,
// Available size
available: usize,
// Orientation for this layout
orientation: direction::Orientation, orientation: direction::Orientation,
} }
struct ChildItem<T> {
child: T,
offset: usize,
length: usize,
}
impl<T> ChildIterator<T> {
fn new(
inner: T, orientation: direction::Orientation, available: usize
) -> Self {
ChildIterator {
inner,
available,
orientation,
offset: 0,
}
}
}
impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
for ChildIterator<I> { for ChildIterator<I> {
type Item = (usize, T); type Item = ChildItem<T>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|child| { self.inner.next().map(|child| {
let previous = self.offset; // Save the current offset.
self.offset += *child.size.get(self.orientation); let offset = self.offset;
(previous, child)
// Allocated width
self.available = self.available.saturating_sub(offset);
let length =
usize::min(self.available, *child.size.get(self.orientation));
self.offset += length;
ChildItem {
offset,
length,
child,
}
}) })
} }
} }
@ -186,6 +222,8 @@ impl LinearLayout {
EventResult::Consumed(None) EventResult::Consumed(None)
} }
// If the event is a mouse event,
// move the focus to the selected view if needed.
fn check_focus_grab(&mut self, event: &Event) { fn check_focus_grab(&mut self, event: &Event) {
if let Event::Mouse { if let Event::Mouse {
offset, offset,
@ -203,22 +241,24 @@ impl LinearLayout {
}; };
// Find the selected child // Find the selected child
// Let's only care about the coordinate for our orientation.
let position = *position.get(self.orientation); let position = *position.get(self.orientation);
let iterator = ChildIterator {
inner: self.children.iter_mut(), // Iterate on the views and find the one
offset: 0, // We need a mutable ref to call take_focus later on.
orientation: self.orientation, for (i, item) in ChildIterator::new(
}; self.children.iter_mut(),
for (i, (offset, child)) in iterator.enumerate() { self.orientation,
let child_size = child.size.get(self.orientation); // TODO: get actual width (not super important)
// eprintln!( usize::max_value(),
// "Offset {:?}, size {:?}, position: {:?}", ).enumerate()
// offset, {
// child_size, // Get the child size:
// position // this will give us the allowed window for a click.
// ); let child_size = item.child.size.get(self.orientation);
if (offset + child_size > position)
&& child.view.take_focus(direction::Direction::none()) if (item.offset + child_size > position)
&& item.child.view.take_focus(direction::Direction::none())
{ {
// eprintln!("It's a match!"); // eprintln!("It's a match!");
self.focus = i; self.focus = i;
@ -242,19 +282,21 @@ fn try_focus(
impl View for LinearLayout { impl View for LinearLayout {
fn draw(&self, printer: &Printer) { fn draw(&self, printer: &Printer) {
// Use pre-computed sizes // Use pre-computed sizes
let mut offset = Vec2::zero(); for (i, item) in ChildIterator::new(
for (i, child) in self.children.iter().enumerate() { self.children.iter(),
self.orientation,
*printer.size.get(self.orientation),
).enumerate()
{
// eprintln!("Printer size: {:?}", printer.size); // eprintln!("Printer size: {:?}", printer.size);
// eprintln!("Child size: {:?}", child.size); // eprintln!("Child size: {:?}", child.size);
// eprintln!("Offset: {:?}", offset); // eprintln!("Offset: {:?}", offset);
let printer = let printer = &printer.sub_printer(
&printer.sub_printer(offset, child.size, i == self.focus); self.orientation.make_vec(item.offset, 0),
child.view.draw(printer); item.child.size,
i == self.focus,
// On the axis given by the orientation, );
// add the child size to the offset. item.child.view.draw(printer);
*self.orientation.get_ref(&mut offset) +=
self.orientation.get(&child.size);
} }
} }
@ -273,12 +315,16 @@ impl View for LinearLayout {
self.required_size(size); self.required_size(size);
} }
// We'll use this guy a few times, but it's a mouthful...
let o = self.orientation; let o = self.orientation;
for child in &mut self.children { for item in
ChildIterator::new(self.children.iter_mut(), o, *size.get(o))
{
// Every item has the same size orthogonal to the layout // Every item has the same size orthogonal to the layout
child.size.set_axis_from(o.swap(), &size); item.child.size.set_axis_from(o.swap(), &size);
child.view.layout(Vec2::min(size, child.size));
item.child.view.layout(size.with_axis(o, item.length));
} }
} }
@ -435,14 +481,14 @@ impl View for LinearLayout {
self.check_focus_grab(&event); self.check_focus_grab(&event);
let result = { let result = {
let mut iterator = ChildIterator { let mut iterator = ChildIterator::new(
inner: self.children.iter_mut(), self.children.iter_mut(),
offset: 0, self.orientation,
orientation: self.orientation, usize::max_value(),
}; );
let (offset, child) = iterator.nth(self.focus).unwrap(); let item = iterator.nth(self.focus).unwrap();
let offset = self.orientation.make_vec(offset, 0); let offset = self.orientation.make_vec(item.offset, 0);
child.view.on_event(event.relativized(offset)) item.child.view.on_event(event.relativized(offset))
}; };
match result { match result {
EventResult::Ignored => match event { EventResult::Ignored => match event {