Add Direction enum

And add a Direction argument to take_focus
This commit is contained in:
Alexandre Bury 2016-07-14 20:27:15 -07:00
parent bd7286a8b2
commit 91fdf96066
17 changed files with 372 additions and 128 deletions

View File

@ -17,6 +17,9 @@ fn main() {
.child(TextView::new("Title").h_align(HAlign::Center)) .child(TextView::new("Title").h_align(HAlign::Center))
// Box the textview, so it doesn't get too wide. // Box the textview, so it doesn't get too wide.
// A 0 height value means it will be unconstrained. // A 0 height value means it will be unconstrained.
.child(BoxView::fixed_width(30, TextView::new(text)))
.child(BoxView::fixed_width(30, TextView::new(text)))
.child(BoxView::fixed_width(30, TextView::new(text)))
.child(BoxView::fixed_width(30, TextView::new(text)))) .child(BoxView::fixed_width(30, TextView::new(text))))
.button("Quit", |s| s.quit()) .button("Quit", |s| s.quit())
.h_align(HAlign::Center)); .h_align(HAlign::Center));

203
src/direction.rs Normal file
View File

@ -0,0 +1,203 @@
//! Direction-related structures.
//!
//! This module defines two main concepts: [Orientation] and [Direction].
//!
//! ### Orientation
//!
//! `Orientation` is a simple enum that can take two values:
//! `Horizontal` or `Vertical`.
//!
//! ### Direction
//!
//! `Direction` is a bit more complex, and can be of two kinds:
//! * Absolute direction: left, up, right, or down
//! * Relative direction: front or back.
//! Its actual direction depends on the orientation.
use vec::Vec2;
/// Describes a vertical or horizontal orientation for a view.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum Orientation {
/// Horizontal orientation
Horizontal,
/// Vertical orientation
Vertical,
}
impl Orientation {
/// Returns the component of `v` corresponding to this orientation.
///
/// (`Horizontal` will return the x value,
/// and `Vertical` will return the y value.)
pub fn get(&self, v: &Vec2) -> usize {
*v.get(*self)
}
/// Returns the other orientation.
pub fn swap(&self) -> Self {
match *self {
Orientation::Horizontal => Orientation::Vertical,
Orientation::Vertical => Orientation::Horizontal,
}
}
/// Returns a mutable reference to the component of the given vector
/// corresponding to this orientation.
pub fn get_ref<'a, 'b>(&'a self, v: &'b mut Vec2) -> &'b mut usize {
match *self {
Orientation::Horizontal => &mut v.x,
Orientation::Vertical => &mut v.y,
}
}
/// Takes an iterator on sizes, and stack them in the current orientation,
/// returning the size of the required bounding box.
///
/// For an horizontal view, returns (Sum(x), Max(y)).
/// For a vertical view, returns (Max(x),Sum(y)).
pub fn stack<'a, T: Iterator<Item = &'a Vec2>>(&self, iter: T) -> Vec2 {
match *self {
Orientation::Horizontal => {
iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(b))
}
Orientation::Vertical => {
iter.fold(Vec2::zero(), |a, b| a.stack_vertical(b))
}
}
}
/// Creates a new `Vec2` with `value` in `self`'s axis.
pub fn make_vec(&self, value: usize) -> Vec2 {
let mut result = Vec2::zero();
*self.get_ref(&mut result) = value;
result
}
}
/// Represents a direction, either absolute or orientation-dependent.
///
/// * Absolute directions are Up, Down, Left, and Right.
/// * Relative directions are Front and Back.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Direction {
/// An absolute direction.
Abs(Absolute),
/// A direction relative to the current orientation.
Rel(Relative),
}
impl Direction {
/// Returns the relative direction for the given orientation.
pub fn relative(self, orientation: Orientation) -> Option<Relative> {
match self {
Direction::Abs(abs) => abs.relative(orientation),
Direction::Rel(rel) => Some(rel),
}
}
/// Returns the absolute direction in the given `orientation`.
pub fn absolute(self, orientation: Orientation) -> Absolute {
match self {
Direction::Abs(abs) => abs,
Direction::Rel(rel) => rel.absolute(orientation),
}
}
/// Shortcut to create `Direction::Rel(Relative::Back)`
pub fn back() -> Self {
Direction::Rel(Relative::Back)
}
/// Shortcut to create `Direction::Rel(Relative::Front)`
pub fn front() -> Self {
Direction::Rel(Relative::Front)
}
/// Shortcut to create `Direction::Abs(Absolute::Left)`
pub fn left() -> Self {
Direction::Abs(Absolute::Left)
}
/// Shortcut to create `Direction::Abs(Absolute::Right)`
pub fn right() -> Self {
Direction::Abs(Absolute::Right)
}
/// Shortcut to create `Direction::Abs(Absolute::Up)`
pub fn up() -> Self {
Direction::Abs(Absolute::Up)
}
/// Shortcut to create `Direction::Abs(Absolute::Down)`
pub fn down() -> Self {
Direction::Abs(Absolute::Down)
}
/// Shortcut to create `Direction::Abs(Absolute::None)`
pub fn none() -> Self {
Direction::Abs(Absolute::None)
}
}
/// Direction relative to an orientation.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Relative {
/// Front relative direction.
///
/// * Horizontally, this means `Left`
/// * Vertically, this means `Up`
///
/// TODO: handle right-to-left?
Front,
/// Back relative direction.
///
/// * Horizontally, this means `Right`
/// * Vertically, this means `Down`.
Back,
}
impl Relative {
/// Returns the absolute direction in the given `orientation`.
pub fn absolute(self, orientation: Orientation) -> Absolute {
match (orientation, self) {
(Orientation::Horizontal, Relative::Front) => Absolute::Left,
(Orientation::Horizontal, Relative::Back) => Absolute::Right,
(Orientation::Vertical, Relative::Front) => Absolute::Up,
(Orientation::Vertical, Relative::Back) => Absolute::Down,
}
}
}
/// Absolute direction (up, down, left, right).
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Absolute {
/// Left
Left,
/// Up
Up,
/// Right
Right,
/// Down
Down,
/// No real direction
None,
}
impl Absolute {
/// Returns the relative direction for the given orientation.
///
/// Returns `None` when the direction does not apply to the given
/// orientation (ex: `Left` and `Vertical`).
pub fn relative(self, orientation: Orientation) -> Option<Relative> {
match (orientation, self) {
(Orientation::Horizontal, Absolute::Left) |
(Orientation::Vertical, Absolute::Up) => Some(Relative::Front),
(Orientation::Horizontal, Absolute::Right) |
(Orientation::Vertical, Absolute::Down) => Some(Relative::Back),
_ => None,
}
}
}

View File

@ -52,12 +52,12 @@ pub mod vec;
pub mod theme; pub mod theme;
pub mod align; pub mod align;
pub mod menu; pub mod menu;
pub mod direction;
// This probably doesn't need to be public? // This probably doesn't need to be public?
mod printer; mod printer;
mod menubar; mod menubar;
mod xy; mod xy;
mod orientation;
mod div; mod div;
mod utf8; mod utf8;
@ -65,7 +65,6 @@ mod utf8;
mod backend; mod backend;
pub use xy::XY; pub use xy::XY;
pub use orientation::Orientation;
pub use printer::Printer; pub use printer::Printer;
use backend::{Backend, NcursesBackend}; use backend::{Backend, NcursesBackend};

View File

@ -89,7 +89,9 @@ impl MenuTree {
} }
/// Adds a actionnable leaf to the end of this tree - chainable variant. /// Adds a actionnable leaf to the end of this tree - chainable variant.
pub fn leaf<F: 'static + Fn(&mut Cursive)>(self, title: &str, cb: F) -> Self { pub fn leaf<F>(self, title: &str, cb: F) -> Self
where F: 'static + Fn(&mut Cursive)
{
self.with(|menu| menu.add_leaf(title, cb)) self.with(|menu| menu.add_leaf(title, cb))
} }

View File

@ -1,61 +0,0 @@
//! Define an Orientation and associated methods.
use vec::Vec2;
/// Describes a vertical or horizontal orientation for a view.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum Orientation {
/// Horizontal orientation
Horizontal,
/// Vertical orientation
Vertical,
}
impl Orientation {
/// Returns the component of `v` corresponding to this orientation.
///
/// (`Horizontal` will return the x value,
/// and `Vertical` will return the y value.)
pub fn get(&self, v: &Vec2) -> usize {
*v.get(*self)
}
/// Returns the other orientation.
pub fn swap(&self) -> Self {
match *self {
Orientation::Horizontal => Orientation::Vertical,
Orientation::Vertical => Orientation::Horizontal,
}
}
/// Returns a mutable reference to the component of the given vector
/// corresponding to this orientation.
pub fn get_ref<'a, 'b>(&'a self, v: &'b mut Vec2) -> &'b mut usize {
match *self {
Orientation::Horizontal => &mut v.x,
Orientation::Vertical => &mut v.y,
}
}
/// Takes an iterator on sizes, and stack them in the current orientation,
/// returning the size of the required bounding box.
///
/// For an horizontal view, returns (Sum(x), Max(y)).
/// For a vertical view, returns (Max(x),Sum(y)).
pub fn stack<'a, T: Iterator<Item = &'a Vec2>>(&self, iter: T) -> Vec2 {
match *self {
Orientation::Horizontal => {
iter.fold(Vec2::zero(), |a, b| a.stack_horizontal(b))
}
Orientation::Vertical => {
iter.fold(Vec2::zero(), |a, b| a.stack_vertical(b))
}
}
}
/// Creates a new `Vec2` with `value` in `self`'s axis.
pub fn make_vec(&self, value: usize) -> Vec2 {
let mut result = Vec2::zero();
*self.get_ref(&mut result) = value;
result
}
}

View File

@ -1,6 +1,6 @@
//! Points on the 2D character grid. //! Points on the 2D character grid.
use XY; use XY;
use orientation::Orientation; use direction::Orientation;
use std::ops::{Add, Div, Mul, Sub}; use std::ops::{Add, Div, Mul, Sub};
use std::cmp::{Ordering, max, min}; use std::cmp::{Ordering, max, min};

View File

@ -1,5 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use direction::Direction;
use theme::ColorStyle; use theme::ColorStyle;
use Cursive; use Cursive;
use vec::Vec2; use vec::Vec2;
@ -58,7 +59,7 @@ impl View for Button {
} }
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, _: Direction) -> bool {
true true
} }
} }

View File

@ -2,6 +2,7 @@ use std::cmp::max;
use std::any::Any; use std::any::Any;
use Cursive; use Cursive;
use direction;
use align::*; use align::*;
use event::*; use event::*;
use theme::ColorStyle; use theme::ColorStyle;
@ -246,16 +247,34 @@ impl View for Dialog {
EventResult::Ignored => { EventResult::Ignored => {
match event { match event {
// Up goes back to the content // Up goes back to the content
Event::Key(Key::Up) | Event::Key(Key::Up) => {
Event::Key(Key::Tab) | if self.content
Event::Shift(Key::Tab) => { .take_focus(direction::Direction::down()) {
if self.content.take_focus() {
self.focus = Focus::Content; self.focus = Focus::Content;
EventResult::Consumed(None) EventResult::Consumed(None)
} else { } else {
EventResult::Ignored EventResult::Ignored
} }
} }
Event::Shift(Key::Tab) => {
if self.content
.take_focus(direction::Direction::back()) {
self.focus = Focus::Content;
EventResult::Consumed(None)
} else {
EventResult::Ignored
}
}
Event::Key(Key::Tab) => {
if self.content
.take_focus(direction::Direction::front()) {
self.focus = Focus::Content;
EventResult::Consumed(None)
} else {
EventResult::Ignored
}
}
// Left and Right move to other buttons // Left and Right move to other buttons
Event::Key(Key::Right) if i + 1 < Event::Key(Key::Right) if i + 1 <
self.buttons self.buttons
@ -276,9 +295,10 @@ impl View for Dialog {
} }
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, source: direction::Direction) -> bool {
// TODO: add a direction to the focus. Meanwhile, takes button first. // Dialogs aren't meant to be used in layouts, so...
if self.content.take_focus() { // Let's be super lazy and not even care about the focus source.
if self.content.take_focus(source) {
self.focus = Focus::Content; self.focus = Focus::Content;
true true
} else if !self.buttons.is_empty() { } else if !self.buttons.is_empty() {

View File

@ -1,6 +1,7 @@
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use direction::Direction;
use theme::{ColorStyle, Effect}; use theme::{ColorStyle, Effect};
use vec::Vec2; use vec::Vec2;
use view::{IdView, View}; use view::{IdView, View};
@ -144,7 +145,7 @@ impl View for EditView {
Vec2::new(self.min_length, 1) Vec2::new(self.min_length, 1)
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, _: Direction) -> bool {
true true
} }

View File

@ -1,5 +1,5 @@
use view::{View, ViewWrapper}; use view::{View, ViewWrapper};
use orientation::Orientation; use direction::Orientation;
use vec::Vec2; use vec::Vec2;
/// Simple wrapper view that asks for all the space it can get. /// Simple wrapper view that asks for all the space it can get.

View File

@ -1,9 +1,9 @@
use XY; use XY;
use direction;
use view::View; use view::View;
use view::SizeCache; use view::SizeCache;
use vec::Vec2; use vec::Vec2;
use Printer; use Printer;
use orientation::Orientation;
use event::{Event, EventResult, Key}; use event::{Event, EventResult, Key};
use std::cmp::min; use std::cmp::min;
@ -11,7 +11,7 @@ use std::cmp::min;
/// Arranges its children linearly according to its orientation. /// Arranges its children linearly according to its orientation.
pub struct LinearLayout { pub struct LinearLayout {
children: Vec<Child>, children: Vec<Child>,
orientation: Orientation, orientation: direction::Orientation,
focus: usize, focus: usize,
cache: Option<XY<SizeCache>>, cache: Option<XY<SizeCache>>,
@ -40,7 +40,7 @@ impl Child {
impl LinearLayout { impl LinearLayout {
/// Creates a new layout with the given orientation. /// Creates a new layout with the given orientation.
pub fn new(orientation: Orientation) -> Self { pub fn new(orientation: direction::Orientation) -> Self {
LinearLayout { LinearLayout {
children: Vec::new(), children: Vec::new(),
orientation: orientation, orientation: orientation,
@ -77,12 +77,12 @@ impl LinearLayout {
/// Creates a new vertical layout. /// Creates a new vertical layout.
pub fn vertical() -> Self { pub fn vertical() -> Self {
LinearLayout::new(Orientation::Vertical) LinearLayout::new(direction::Orientation::Vertical)
} }
/// Creates a new horizontal layout. /// Creates a new horizontal layout.
pub fn horizontal() -> Self { pub fn horizontal() -> Self {
LinearLayout::new(Orientation::Horizontal) LinearLayout::new(direction::Orientation::Horizontal)
} }
// If the cache can be used, return the cached size. // If the cache can be used, return the cached size.
@ -110,15 +110,60 @@ impl LinearLayout {
.any(View::needs_relayout) .any(View::needs_relayout)
} }
/// Returns a cyclic mutable iterator starting with the child in focus
fn iter_mut<'a>(&'a mut self, from_focus: bool,
direction: direction::Relative)
-> Box<Iterator<Item = (usize, &'a mut Child)> + 'a> {
match direction {
direction::Relative::Front => {
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 {
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)
}
fn focus_prev(&mut self) -> EventResult { fn focus_prev(&mut self) -> EventResult {
if let Some(i) = self.children[..self.focus] if let Some(i) = self.children[..self.focus]
.iter_mut() .iter_mut()
.rev() .rev()
.map(Child::as_mut) .map(Child::as_mut)
.position(View::take_focus) { .position(|v| v.take_focus(direction::Direction::back())) {
// We're looking at the list in reverse // We're looking at the list in reverse
self.focus -= i+1; self.focus -= i + 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} else { } else {
EventResult::Ignored EventResult::Ignored
@ -130,7 +175,7 @@ impl LinearLayout {
.iter_mut() .iter_mut()
.rev() .rev()
.map(Child::as_mut) .map(Child::as_mut)
.position(View::take_focus) { .position(|v| v.take_focus(direction::Direction::front())) {
// Our slice doesn't start at 0 // Our slice doesn't start at 0
self.focus += i + 1; self.focus += i + 1;
EventResult::Consumed(None) EventResult::Consumed(None)
@ -140,6 +185,15 @@ impl LinearLayout {
} }
} }
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 { impl View for LinearLayout {
fn draw(&mut self, printer: &Printer) { fn draw(&mut self, printer: &Printer) {
// Use pre-computed sizes // Use pre-computed sizes
@ -282,16 +336,25 @@ impl View for LinearLayout {
compromise compromise
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, source: direction::Direction) -> bool {
if let Some(i) = self.children // In what order will we iterate on the children?
.iter_mut() let rel = source.relative(self.orientation);
.map(Child::as_mut) // We activate from_focus only if coming from the "sides".
.position(View::take_focus) { 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; self.focus = i;
true true
} else {
false
}
} }
fn on_event(&mut self, event: Event) -> EventResult { fn on_event(&mut self, event: Event) -> EventResult {
@ -299,31 +362,36 @@ impl View for LinearLayout {
EventResult::Ignored => { EventResult::Ignored => {
match event { match event {
Event::Shift(Key::Tab) if self.focus > 0 => { Event::Shift(Key::Tab) if self.focus > 0 => {
self.focus_prev() self.move_focus(direction::Direction::back())
} }
Event::Key(Key::Tab) if self.focus + 1 < Event::Key(Key::Tab) if self.focus + 1 <
self.children.len() => { self.children.len() => {
self.focus_next() self.move_focus(direction::Direction::front())
} }
Event::Key(Key::Left) if self.orientation == Event::Key(Key::Left)
Orientation::Horizontal && if self.orientation ==
direction::Orientation::Horizontal &&
self.focus > 0 => { self.focus > 0 => {
self.focus_prev() self.move_focus(direction::Direction::right())
} }
Event::Key(Key::Up) if self.orientation == Event::Key(Key::Up) if self.orientation ==
Orientation::Vertical && direction::Orientation::Vertical &&
self.focus > 0 => self.focus_prev(), self.focus > 0 => {
Event::Key(Key::Right) if self.orientation == self.move_focus(direction::Direction::down())
Orientation::Horizontal &&
self.focus + 1 <
self.children.len() => {
self.focus_next()
} }
Event::Key(Key::Down) if self.orientation == Event::Key(Key::Right)
Orientation::Vertical && if self.orientation ==
direction::Orientation::Horizontal &&
self.focus + 1 < self.focus + 1 <
self.children.len() => { self.children.len() => {
self.focus_next() 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, _ => EventResult::Ignored,
} }

View File

@ -25,7 +25,8 @@
//! * By default, `View::layout()` should be called before any call to //! * By default, `View::layout()` should be called before any call to
//! `View::draw()` with the same available size. The only exceptions is //! `View::draw()` with the same available size. The only exceptions is
//! when both following conditions are met: //! when both following conditions are met:
//! * The available size has not changed since the last call to `View::layout()` //! * The available size has not changed since the last call to
//! `View::layout()`
//! * `View::needs_relayout()` returns `false` //! * `View::needs_relayout()` returns `false`
//! //!
//! In this case, it is safe to omit the call to `View::layout()`. //! In this case, it is safe to omit the call to `View::layout()`.
@ -65,6 +66,7 @@ mod tracked_view;
use std::any::Any; use std::any::Any;
use XY; use XY;
use direction::Direction;
use event::{Event, EventResult}; use event::{Event, EventResult};
use vec::Vec2; use vec::Vec2;
use Printer; use Printer;
@ -135,7 +137,11 @@ pub trait View {
} }
/// This view is offered focus. Will it take it? /// This view is offered focus. Will it take it?
fn take_focus(&mut self) -> bool { ///
/// `source` indicates where the focus comes from.
/// When the source is unclear, `Front` is usually used.
fn take_focus(&mut self, source: Direction) -> bool {
let _ = source;
false false
} }
} }

View File

@ -2,6 +2,7 @@ use std::cmp::min;
use std::rc::Rc; use std::rc::Rc;
use Cursive; use Cursive;
use direction::Direction;
use view::{IdView, View}; use view::{IdView, View};
use align::{Align, HAlign, VAlign}; use align::{Align, HAlign, VAlign};
use view::scroll::ScrollBase; use view::scroll::ScrollBase;
@ -215,7 +216,7 @@ impl<T: 'static> View for SelectView<T> {
EventResult::Consumed(None) EventResult::Consumed(None)
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, _: Direction) -> bool {
true true
} }

View File

@ -1,5 +1,6 @@
use std::any::Any; use std::any::Any;
use direction::Direction;
use backend::Backend; use backend::Backend;
use vec::Vec2; use vec::Vec2;
use view::{Offset, Position, Selector, ShadowView, View}; use view::{Offset, Position, Selector, ShadowView, View};
@ -96,7 +97,7 @@ impl View for StackView {
// We do it here instead of when adding a new layer because...? // We do it here instead of when adding a new layer because...?
// (TODO: try to make it during layer addition) // (TODO: try to make it during layer addition)
if layer.virgin { if layer.virgin {
layer.view.take_focus(); layer.view.take_focus(Direction::none());
layer.virgin = false; layer.virgin = false;
} }
} }
@ -111,10 +112,10 @@ impl View for StackView {
.fold(Vec2::new(1, 1), Vec2::max) .fold(Vec2::new(1, 1), Vec2::max)
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, source: Direction) -> bool {
match self.layers.last_mut() { match self.layers.last_mut() {
None => false, None => false,
Some(mut v) => v.view.take_focus(), Some(mut v) => v.view.take_focus(source),
} }
} }

View File

@ -1,4 +1,5 @@
use XY; use XY;
use direction::Direction;
use vec::Vec2; use vec::Vec2;
use view::View; use view::View;
use view::SizeCache; use view::SizeCache;
@ -239,7 +240,7 @@ impl View for TextView {
size.or_min((self.width.unwrap_or(0), self.rows.len())) size.or_min((self.width.unwrap_or(0), self.rows.len()))
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, _: Direction) -> bool {
self.scrollbase.scrollable() self.scrollbase.scrollable()
} }

View File

@ -1,5 +1,6 @@
use std::any::Any; use std::any::Any;
use direction::Direction;
use vec::Vec2; use vec::Vec2;
use view::{Selector, View}; use view::{Selector, View};
use Printer; use Printer;
@ -37,8 +38,8 @@ pub trait ViewWrapper {
} }
/// Wraps the `take_focus` method. /// Wraps the `take_focus` method.
fn wrap_take_focus(&mut self) -> bool { fn wrap_take_focus(&mut self, source: Direction) -> bool {
self.get_view_mut().take_focus() self.get_view_mut().take_focus(source)
} }
/// Wraps the `find` method. /// Wraps the `find` method.
@ -69,8 +70,8 @@ impl<T: ViewWrapper> View for T {
self.wrap_layout(size); self.wrap_layout(size);
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self, source: Direction) -> bool {
self.wrap_take_focus() self.wrap_take_focus(source)
} }
fn find(&mut self, selector: &Selector) -> Option<&mut Any> { fn find(&mut self, selector: &Selector) -> Option<&mut Any> {

View File

@ -1,4 +1,4 @@
use orientation::Orientation; use direction::Orientation;
use std::iter; use std::iter;
@ -46,14 +46,12 @@ impl<T> XY<T> {
} }
/// Returns a new XY by calling `f` on `self` and `other` for each axis. /// Returns a new XY by calling `f` on `self` and `other` for each axis.
pub fn zip_map<U,V,F: Fn(T,U) -> V>(self, other: XY<U>, f: F) -> XY<V> { pub fn zip_map<U, V, F: Fn(T, U) -> V>(self, other: XY<U>, f: F) -> XY<V> {
XY::new(f(self.x, other.x), XY::new(f(self.x, other.x), f(self.y, other.y))
f(self.y, other.y))
} }
} }
impl <T> XY<Option<T>> { impl<T> XY<Option<T>> {
/// Returns a new XY by calling `unwrap_or` on each axis. /// Returns a new XY by calling `unwrap_or` on each axis.
pub fn unwrap_or(self, other: XY<T>) -> XY<T> { pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
self.zip_map(other, |s, o| s.unwrap_or(o)) self.zip_map(other, |s, o| s.unwrap_or(o))