mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Add Direction
enum
And add a Direction argument to take_focus
This commit is contained in:
parent
bd7286a8b2
commit
91fdf96066
@ -17,6 +17,9 @@ fn main() {
|
||||
.child(TextView::new("Title").h_align(HAlign::Center))
|
||||
// Box the textview, so it doesn't get too wide.
|
||||
// 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))))
|
||||
.button("Quit", |s| s.quit())
|
||||
.h_align(HAlign::Center));
|
||||
|
203
src/direction.rs
Normal file
203
src/direction.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -52,12 +52,12 @@ pub mod vec;
|
||||
pub mod theme;
|
||||
pub mod align;
|
||||
pub mod menu;
|
||||
pub mod direction;
|
||||
|
||||
// This probably doesn't need to be public?
|
||||
mod printer;
|
||||
mod menubar;
|
||||
mod xy;
|
||||
mod orientation;
|
||||
|
||||
mod div;
|
||||
mod utf8;
|
||||
@ -65,7 +65,6 @@ mod utf8;
|
||||
mod backend;
|
||||
|
||||
pub use xy::XY;
|
||||
pub use orientation::Orientation;
|
||||
pub use printer::Printer;
|
||||
|
||||
use backend::{Backend, NcursesBackend};
|
||||
|
@ -89,7 +89,9 @@ impl MenuTree {
|
||||
}
|
||||
|
||||
/// 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))
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
//! Points on the 2D character grid.
|
||||
use XY;
|
||||
use orientation::Orientation;
|
||||
use direction::Orientation;
|
||||
|
||||
use std::ops::{Add, Div, Mul, Sub};
|
||||
use std::cmp::{Ordering, max, min};
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use direction::Direction;
|
||||
use theme::ColorStyle;
|
||||
use Cursive;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use std::cmp::max;
|
||||
use std::any::Any;
|
||||
|
||||
use Cursive;
|
||||
use direction;
|
||||
use align::*;
|
||||
use event::*;
|
||||
use theme::ColorStyle;
|
||||
@ -246,16 +247,34 @@ impl View for Dialog {
|
||||
EventResult::Ignored => {
|
||||
match event {
|
||||
// Up goes back to the content
|
||||
Event::Key(Key::Up) |
|
||||
Event::Key(Key::Tab) |
|
||||
Event::Shift(Key::Tab) => {
|
||||
if self.content.take_focus() {
|
||||
Event::Key(Key::Up) => {
|
||||
if self.content
|
||||
.take_focus(direction::Direction::down()) {
|
||||
self.focus = Focus::Content;
|
||||
EventResult::Consumed(None)
|
||||
} else {
|
||||
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
|
||||
Event::Key(Key::Right) if i + 1 <
|
||||
self.buttons
|
||||
@ -276,9 +295,10 @@ impl View for Dialog {
|
||||
}
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) -> bool {
|
||||
// TODO: add a direction to the focus. Meanwhile, takes button first.
|
||||
if self.content.take_focus() {
|
||||
fn take_focus(&mut self, source: direction::Direction) -> bool {
|
||||
// Dialogs aren't meant to be used in layouts, so...
|
||||
// Let's be super lazy and not even care about the focus source.
|
||||
if self.content.take_focus(source) {
|
||||
self.focus = Focus::Content;
|
||||
true
|
||||
} else if !self.buttons.is_empty() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use direction::Direction;
|
||||
use theme::{ColorStyle, Effect};
|
||||
use vec::Vec2;
|
||||
use view::{IdView, View};
|
||||
@ -144,7 +145,7 @@ impl View for EditView {
|
||||
Vec2::new(self.min_length, 1)
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) -> bool {
|
||||
fn take_focus(&mut self, _: Direction) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use view::{View, ViewWrapper};
|
||||
use orientation::Orientation;
|
||||
use direction::Orientation;
|
||||
use vec::Vec2;
|
||||
|
||||
/// Simple wrapper view that asks for all the space it can get.
|
||||
|
@ -1,9 +1,9 @@
|
||||
use XY;
|
||||
use direction;
|
||||
use view::View;
|
||||
use view::SizeCache;
|
||||
use vec::Vec2;
|
||||
use Printer;
|
||||
use orientation::Orientation;
|
||||
use event::{Event, EventResult, Key};
|
||||
|
||||
use std::cmp::min;
|
||||
@ -11,7 +11,7 @@ use std::cmp::min;
|
||||
/// Arranges its children linearly according to its orientation.
|
||||
pub struct LinearLayout {
|
||||
children: Vec<Child>,
|
||||
orientation: Orientation,
|
||||
orientation: direction::Orientation,
|
||||
focus: usize,
|
||||
|
||||
cache: Option<XY<SizeCache>>,
|
||||
@ -40,7 +40,7 @@ impl Child {
|
||||
|
||||
impl LinearLayout {
|
||||
/// Creates a new layout with the given orientation.
|
||||
pub fn new(orientation: Orientation) -> Self {
|
||||
pub fn new(orientation: direction::Orientation) -> Self {
|
||||
LinearLayout {
|
||||
children: Vec::new(),
|
||||
orientation: orientation,
|
||||
@ -77,12 +77,12 @@ impl LinearLayout {
|
||||
|
||||
/// Creates a new vertical layout.
|
||||
pub fn vertical() -> Self {
|
||||
LinearLayout::new(Orientation::Vertical)
|
||||
LinearLayout::new(direction::Orientation::Vertical)
|
||||
}
|
||||
|
||||
/// Creates a new horizontal layout.
|
||||
pub fn horizontal() -> Self {
|
||||
LinearLayout::new(Orientation::Horizontal)
|
||||
LinearLayout::new(direction::Orientation::Horizontal)
|
||||
}
|
||||
|
||||
// If the cache can be used, return the cached size.
|
||||
@ -110,15 +110,60 @@ impl LinearLayout {
|
||||
.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 {
|
||||
if let Some(i) = self.children[..self.focus]
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.map(Child::as_mut)
|
||||
.position(View::take_focus) {
|
||||
.position(|v| v.take_focus(direction::Direction::back())) {
|
||||
|
||||
// We're looking at the list in reverse
|
||||
self.focus -= i+1;
|
||||
self.focus -= i + 1;
|
||||
EventResult::Consumed(None)
|
||||
} else {
|
||||
EventResult::Ignored
|
||||
@ -130,7 +175,7 @@ impl LinearLayout {
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.map(Child::as_mut)
|
||||
.position(View::take_focus) {
|
||||
.position(|v| v.take_focus(direction::Direction::front())) {
|
||||
// Our slice doesn't start at 0
|
||||
self.focus += i + 1;
|
||||
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 {
|
||||
fn draw(&mut self, printer: &Printer) {
|
||||
// Use pre-computed sizes
|
||||
@ -282,16 +336,25 @@ impl View for LinearLayout {
|
||||
compromise
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) -> bool {
|
||||
if let Some(i) = self.children
|
||||
.iter_mut()
|
||||
.map(Child::as_mut)
|
||||
.position(View::take_focus) {
|
||||
self.focus = i;
|
||||
true
|
||||
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".
|
||||
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 {
|
||||
false
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
self.focus = i;
|
||||
true
|
||||
}
|
||||
|
||||
fn on_event(&mut self, event: Event) -> EventResult {
|
||||
@ -299,31 +362,36 @@ impl View for LinearLayout {
|
||||
EventResult::Ignored => {
|
||||
match event {
|
||||
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 <
|
||||
self.children.len() => {
|
||||
self.focus_next()
|
||||
self.move_focus(direction::Direction::front())
|
||||
}
|
||||
Event::Key(Key::Left) if self.orientation ==
|
||||
Orientation::Horizontal &&
|
||||
self.focus > 0 => {
|
||||
self.focus_prev()
|
||||
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 ==
|
||||
Orientation::Vertical &&
|
||||
self.focus > 0 => self.focus_prev(),
|
||||
Event::Key(Key::Right) if self.orientation ==
|
||||
Orientation::Horizontal &&
|
||||
self.focus + 1 <
|
||||
self.children.len() => {
|
||||
self.focus_next()
|
||||
direction::Orientation::Vertical &&
|
||||
self.focus > 0 => {
|
||||
self.move_focus(direction::Direction::down())
|
||||
}
|
||||
Event::Key(Key::Down) if self.orientation ==
|
||||
Orientation::Vertical &&
|
||||
self.focus + 1 <
|
||||
self.children.len() => {
|
||||
self.focus_next()
|
||||
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,
|
||||
}
|
||||
|
@ -25,7 +25,8 @@
|
||||
//! * By default, `View::layout()` should be called before any call to
|
||||
//! `View::draw()` with the same available size. The only exceptions is
|
||||
//! 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`
|
||||
//!
|
||||
//! 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 XY;
|
||||
use direction::Direction;
|
||||
use event::{Event, EventResult};
|
||||
use vec::Vec2;
|
||||
use Printer;
|
||||
@ -135,7 +137,11 @@ pub trait View {
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
@ -178,7 +184,7 @@ impl SizeCache {
|
||||
/// * for each dimension, `constrained = (size == req)`
|
||||
fn build(size: Vec2, req: Vec2) -> XY<Self> {
|
||||
XY::new(SizeCache::new(size.x, size.x == req.x),
|
||||
SizeCache::new(size.y, size.y == req.y))
|
||||
SizeCache::new(size.y, size.y == req.y))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use std::cmp::min;
|
||||
use std::rc::Rc;
|
||||
|
||||
use Cursive;
|
||||
use direction::Direction;
|
||||
use view::{IdView, View};
|
||||
use align::{Align, HAlign, VAlign};
|
||||
use view::scroll::ScrollBase;
|
||||
@ -215,7 +216,7 @@ impl<T: 'static> View for SelectView<T> {
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) -> bool {
|
||||
fn take_focus(&mut self, _: Direction) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::any::Any;
|
||||
|
||||
use direction::Direction;
|
||||
use backend::Backend;
|
||||
use vec::Vec2;
|
||||
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...?
|
||||
// (TODO: try to make it during layer addition)
|
||||
if layer.virgin {
|
||||
layer.view.take_focus();
|
||||
layer.view.take_focus(Direction::none());
|
||||
layer.virgin = false;
|
||||
}
|
||||
}
|
||||
@ -111,10 +112,10 @@ impl View for StackView {
|
||||
.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() {
|
||||
None => false,
|
||||
Some(mut v) => v.view.take_focus(),
|
||||
Some(mut v) => v.view.take_focus(source),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use XY;
|
||||
use direction::Direction;
|
||||
use vec::Vec2;
|
||||
use view::View;
|
||||
use view::SizeCache;
|
||||
@ -239,7 +240,7 @@ impl View for TextView {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::any::Any;
|
||||
|
||||
use direction::Direction;
|
||||
use vec::Vec2;
|
||||
use view::{Selector, View};
|
||||
use Printer;
|
||||
@ -37,8 +38,8 @@ pub trait ViewWrapper {
|
||||
}
|
||||
|
||||
/// Wraps the `take_focus` method.
|
||||
fn wrap_take_focus(&mut self) -> bool {
|
||||
self.get_view_mut().take_focus()
|
||||
fn wrap_take_focus(&mut self, source: Direction) -> bool {
|
||||
self.get_view_mut().take_focus(source)
|
||||
}
|
||||
|
||||
/// Wraps the `find` method.
|
||||
@ -69,8 +70,8 @@ impl<T: ViewWrapper> View for T {
|
||||
self.wrap_layout(size);
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) -> bool {
|
||||
self.wrap_take_focus()
|
||||
fn take_focus(&mut self, source: Direction) -> bool {
|
||||
self.wrap_take_focus(source)
|
||||
}
|
||||
|
||||
fn find(&mut self, selector: &Selector) -> Option<&mut Any> {
|
||||
|
10
src/xy.rs
10
src/xy.rs
@ -1,4 +1,4 @@
|
||||
use orientation::Orientation;
|
||||
use direction::Orientation;
|
||||
|
||||
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.
|
||||
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),
|
||||
f(self.y, other.y))
|
||||
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), 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.
|
||||
pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
|
||||
self.zip_map(other, |s, o| s.unwrap_or(o))
|
||||
|
Loading…
Reference in New Issue
Block a user