cursive/src/views/linear_layout.rs

422 lines
13 KiB
Rust
Raw Normal View History

2016-10-02 22:22:29 +00:00
use Printer;
use With;
2016-10-02 22:22:29 +00:00
use XY;
use direction;
2016-03-15 22:37:57 +00:00
use event::{Event, EventResult, Key};
2016-07-17 01:18:33 +00:00
use std::any::Any;
2016-07-13 08:19:05 +00:00
use std::cmp::min;
2016-10-02 22:22:29 +00:00
use vec::Vec2;
use view::{Selector, SizeCache};
use view::View;
2016-07-13 08:19:05 +00:00
2015-06-08 22:38:10 +00:00
/// Arranges its children linearly according to its orientation.
pub struct LinearLayout {
children: Vec<Child>,
orientation: direction::Orientation,
2015-06-08 22:11:44 +00:00
focus: usize,
2016-07-13 08:19:05 +00:00
cache: Option<XY<SizeCache>>,
}
2015-06-08 22:38:10 +00:00
struct Child {
view: Box<View>,
size: Vec2,
weight: usize,
}
2016-07-13 08:19:05 +00:00
impl Child {
// Compute and caches the required size.
fn required_size(&mut self, req: Vec2) -> Vec2 {
self.size = self.view.required_size(req);
2016-07-13 08:19:05 +00:00
self.size
}
2016-07-15 05:32:43 +00:00
fn as_view(&self) -> &View {
&*self.view
}
2016-07-13 08:19:05 +00:00
}
fn cap<'a, I: Iterator<Item = &'a mut usize>>(iter: I, max: usize) {
let mut available = max;
for item in iter {
if *item > available {
*item = available;
}
available -= *item;
}
}
impl LinearLayout {
2015-06-08 22:38:10 +00:00
/// Creates a new layout with the given orientation.
pub fn new(orientation: direction::Orientation) -> Self {
LinearLayout {
children: Vec::new(),
orientation: orientation,
2015-06-08 22:11:44 +00:00
focus: 0,
2016-07-13 08:19:05 +00:00
cache: None,
}
}
2015-06-08 22:38:10 +00:00
/// Modifies the weight of the last child added.
///
/// It is an error to call this before adding a child (and it will panic).
pub fn weight(mut self, weight: usize) -> Self {
self.children.last_mut().unwrap().weight = weight;
self
}
2015-06-08 22:38:10 +00:00
/// Adds a child to the layout.
///
/// Chainable variant.
pub fn child<V: View + 'static>(self, view: V) -> Self {
self.with(|s| s.add_child(view))
}
/// Adds a child to the layout.
pub fn add_child<V: View + 'static>(&mut self, view: V) {
self.children.push(Child {
view: Box::new(view),
size: Vec2::zero(),
weight: 0,
});
2016-07-13 08:19:05 +00:00
self.invalidate();
}
2016-07-13 08:19:05 +00:00
// Invalidate the view, to request a layout next time
fn invalidate(&mut self) {
self.cache = None;
}
2015-06-08 22:38:10 +00:00
/// Creates a new vertical layout.
pub fn vertical() -> Self {
LinearLayout::new(direction::Orientation::Vertical)
}
2015-06-08 22:38:10 +00:00
/// Creates a new horizontal layout.
pub fn horizontal() -> Self {
LinearLayout::new(direction::Orientation::Horizontal)
}
2016-07-13 08:19:05 +00:00
// If the cache can be used, return the cached size.
// Otherwise, return None.
fn get_cache(&self, req: Vec2) -> Option<Vec2> {
match self.cache {
None => None,
Some(ref cache) => {
// Is our cache even valid?
// Also, is any child invalidating the layout?
2017-10-12 23:38:55 +00:00
if cache.zip_map(req, SizeCache::accept).both()
&& self.children_are_sleeping()
{
2016-07-13 08:19:05 +00:00
Some(cache.map(|s| s.value))
} else {
None
}
}
}
}
fn children_are_sleeping(&self) -> bool {
!self.children
.iter()
2016-07-15 05:32:43 +00:00
.map(Child::as_view)
2016-07-13 08:19:05 +00:00
.any(View::needs_relayout)
}
/// Returns a cyclic mutable iterator starting with the child in focus
2017-10-12 23:38:55 +00:00
fn iter_mut<'a>(
&'a mut self, from_focus: bool, source: direction::Relative
) -> Box<Iterator<Item = (usize, &mut Child)> + 'a> {
match source {
direction::Relative::Front => {
2016-10-02 22:22:29 +00:00
let start = if from_focus { self.focus } else { 0 };
Box::new(self.children.iter_mut().enumerate().skip(start))
}
direction::Relative::Back => {
let end = if from_focus {
self.focus + 1
} else {
self.children.len()
};
Box::new(self.children[..end].iter_mut().enumerate().rev())
}
}
}
fn move_focus(&mut self, source: direction::Direction) -> EventResult {
2017-10-12 23:38:55 +00:00
let i = if let Some(i) =
source.relative(self.orientation).and_then(|rel| {
// The iterator starts at the focused element.
// We don't want that one.
self.iter_mut(true, rel)
.skip(1)
.filter_map(|p| try_focus(p, source))
.next()
}) {
i
} else {
return EventResult::Ignored;
};
self.focus = i;
EventResult::Consumed(None)
}
}
2017-10-12 23:38:55 +00:00
fn try_focus(
(i, child): (usize, &mut Child), source: direction::Direction
) -> Option<usize> {
if child.view.take_focus(source) {
Some(i)
} else {
None
}
}
impl View for LinearLayout {
fn draw(&self, printer: &Printer) {
// Use pre-computed sizes
let mut offset = Vec2::zero();
for (i, child) in self.children.iter().enumerate() {
2016-07-11 02:11:21 +00:00
let printer =
&printer.sub_printer(offset, child.size, i == self.focus);
child.view.draw(printer);
// On the axis given by the orientation,
// add the child size to the offset.
2017-10-12 23:38:55 +00:00
*self.orientation.get_ref(&mut offset) +=
self.orientation.get(&child.size);
}
}
fn needs_relayout(&self) -> bool {
2016-07-13 08:19:05 +00:00
if self.cache.is_none() {
return true;
}
2016-07-13 08:19:05 +00:00
!self.children_are_sleeping()
}
fn layout(&mut self, size: Vec2) {
2016-07-13 08:19:05 +00:00
// If we can get away without breaking a sweat, you can bet we will.
if self.get_cache(size).is_none() {
self.required_size(size);
2016-07-13 08:19:05 +00:00
}
let o = self.orientation;
2016-07-13 08:19:05 +00:00
for child in &mut self.children {
// Every item has the same size orthogonal to the layout
child.size.set_axis_from(o.swap(), &size);
child.view.layout(size.with_axis_from(o, &child.size));
2016-07-13 08:19:05 +00:00
}
}
fn required_size(&mut self, req: Vec2) -> Vec2 {
2016-07-13 08:19:05 +00:00
// Did anything change since last time?
if let Some(size) = self.get_cache(req) {
return size;
}
// First, make a naive scenario: everything will work fine.
2016-03-15 22:37:57 +00:00
let sizes: Vec<Vec2> = self.children
2016-07-10 02:05:51 +00:00
.iter_mut()
.map(|c| c.required_size(req))
2016-07-10 02:05:51 +00:00
.collect();
debug!("Ideal sizes: {:?}", sizes);
2016-07-13 08:19:05 +00:00
let ideal = self.orientation.stack(sizes.iter());
debug!("Ideal result: {:?}", ideal);
2016-07-13 08:19:05 +00:00
// Does it fit?
if ideal.fits_in(req) {
// Champagne!
self.cache = Some(SizeCache::build(ideal, req));
return ideal;
}
// Ok, so maybe it didn't. Budget cuts, everyone.
// Let's pretend we have almost no space in this direction.
2016-07-26 16:55:22 +00:00
let budget_req = req.with_axis(self.orientation, 1);
debug!("Budget req: {:?}", budget_req);
2016-07-13 08:19:05 +00:00
// See how they like it that way
2016-07-13 08:19:05 +00:00
let min_sizes: Vec<Vec2> = self.children
.iter_mut()
.map(|c| c.required_size(budget_req))
2016-07-13 08:19:05 +00:00
.collect();
let desperate = self.orientation.stack(min_sizes.iter());
debug!("Min sizes: {:?}", min_sizes);
debug!("Desperate: {:?}", desperate);
2016-07-13 08:19:05 +00:00
// This is the lowest we'll ever go. It better fit at least.
let orientation = self.orientation;
2016-07-13 08:19:05 +00:00
if !desperate.fits_in(req) {
// Just give up...
// TODO: hard-cut
2017-10-12 23:38:55 +00:00
cap(
self.children
.iter_mut()
.map(|c| c.size.get_mut(orientation)),
2017-10-12 23:38:55 +00:00
*req.get(self.orientation),
);
// TODO: print some error message or something
debug!("Seriously? {:?} > {:?}???", desperate, req);
2016-07-17 05:05:28 +00:00
// self.cache = Some(SizeCache::build(desperate, req));
self.cache = None;
2016-07-13 08:19:05 +00:00
return desperate;
}
// This here is how much we're generously offered
2017-08-14 23:32:01 +00:00
// (We just checked that req >= desperate, so the subtraction is safe
2016-07-13 08:19:05 +00:00
let mut available = self.orientation.get(&(req - desperate));
debug!("Available: {:?}", available);
2016-07-13 08:19:05 +00:00
// Here, we have to make a compromise between the ideal
// and the desperate solutions.
2017-10-12 23:38:55 +00:00
let mut overweight: Vec<(usize, usize)> = sizes
.iter()
2016-07-13 08:19:05 +00:00
.map(|v| self.orientation.get(v))
.zip(min_sizes.iter().map(|v| self.orientation.get(v)))
2017-08-14 23:32:01 +00:00
.map(|(a, b)| a.saturating_sub(b))
2016-07-13 08:19:05 +00:00
.enumerate()
.collect();
debug!("Overweight: {:?}", overweight);
2016-07-13 08:19:05 +00:00
// So... distribute `available` to reduce the overweight...
// TODO: use child weight in the distribution...
// We'll give everyone his share of what we have left,
// starting with those who ask the least.
2016-07-13 08:19:05 +00:00
overweight.sort_by_key(|&(_, weight)| weight);
let mut allocations = vec![0; overweight.len()];
for (i, &(j, weight)) in overweight.iter().enumerate() {
// This is the number of people we still have to feed.
2016-07-13 08:19:05 +00:00
let remaining = overweight.len() - i;
// How much we can spare on each one
2016-07-13 08:19:05 +00:00
let budget = available / remaining;
// Maybe he doesn't even need that much?
2016-07-13 08:19:05 +00:00
let spent = min(budget, weight);
allocations[j] = spent;
available -= spent;
}
debug!("Allocations: {:?}", allocations);
2016-07-13 08:19:05 +00:00
// Final lengths are the minimum ones + generous allocations
2017-10-12 23:38:55 +00:00
let final_lengths: Vec<Vec2> = min_sizes
.iter()
2016-07-13 08:19:05 +00:00
.map(|v| self.orientation.get(v))
.zip(allocations.iter())
.map(|(a, b)| a + b)
2016-07-26 16:55:22 +00:00
.map(|l| req.with_axis(self.orientation, l))
2016-07-13 08:19:05 +00:00
.collect();
debug!("Final sizes: {:?}", final_lengths);
2016-07-13 08:19:05 +00:00
// Let's ask everyone one last time. Everyone should be happy.
// (But they may ask more on the other axis.)
2016-07-13 08:19:05 +00:00
let final_sizes: Vec<Vec2> = self.children
.iter_mut()
.enumerate()
.map(|(i, c)| c.required_size(final_lengths[i]))
2016-07-13 08:19:05 +00:00
.collect();
debug!("Final sizes2: {:?}", final_sizes);
// Let's stack everything to see what it looks like.
2016-07-13 08:19:05 +00:00
let compromise = self.orientation.stack(final_sizes.iter());
// Phew, that was a lot of work! I'm not doing it again.
2016-07-13 08:19:05 +00:00
self.cache = Some(SizeCache::build(compromise, req));
2016-07-13 08:19:05 +00:00
compromise
}
2015-06-08 22:11:44 +00:00
fn take_focus(&mut self, source: direction::Direction) -> bool {
// In what order will we iterate on the children?
let rel = source.relative(self.orientation);
// We activate from_focus only if coming from the "sides".
2017-10-12 23:38:55 +00:00
let i = if let Some(i) = self.iter_mut(
rel.is_none(),
rel.unwrap_or(direction::Relative::Front),
).filter_map(|p| try_focus(p, source))
.next()
{
// ... we can't update `self.focus` here,
// because rustc thinks we still borrow `self`.
// :(
i
} else {
return false;
};
self.focus = i;
true
}
2015-06-08 22:11:44 +00:00
fn on_event(&mut self, event: Event) -> EventResult {
match self.children[self.focus].view.on_event(event.clone()) {
2017-10-12 23:38:55 +00:00
EventResult::Ignored => match event {
Event::Shift(Key::Tab) if self.focus > 0 => {
self.move_focus(direction::Direction::back())
2016-03-15 22:37:57 +00:00
}
2017-10-12 23:38:55 +00:00
Event::Key(Key::Tab)
if self.focus + 1 < self.children.len() =>
{
self.move_focus(direction::Direction::front())
}
Event::Key(Key::Left)
if self.orientation == direction::Orientation::Horizontal
&& self.focus > 0 =>
{
self.move_focus(direction::Direction::right())
}
Event::Key(Key::Up)
if self.orientation == direction::Orientation::Vertical
&& self.focus > 0 =>
{
self.move_focus(direction::Direction::down())
}
Event::Key(Key::Right)
if self.orientation == direction::Orientation::Horizontal
&& self.focus + 1 < self.children.len() =>
{
self.move_focus(direction::Direction::left())
}
Event::Key(Key::Down)
if self.orientation == direction::Orientation::Vertical
&& self.focus + 1 < self.children.len() =>
{
self.move_focus(direction::Direction::up())
}
_ => EventResult::Ignored,
},
2015-06-08 22:11:44 +00:00
res => res,
}
}
2016-07-17 01:18:33 +00:00
2017-10-12 23:38:55 +00:00
fn call_on_any<'a>(
&mut self, selector: &Selector,
mut callback: Box<FnMut(&mut Any) + 'a>,
) {
for child in &mut self.children {
2017-10-12 23:38:55 +00:00
child
.view
.call_on_any(selector, Box::new(|any| callback(any)));
}
2016-07-17 01:18:33 +00:00
}
2017-03-25 21:50:52 +00:00
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
for (i, child) in self.children.iter_mut().enumerate() {
if child.view.focus_view(selector).is_ok() {
self.focus = i;
return Ok(());
}
}
Err(())
}
}