Add View::focus_view

This commit is contained in:
Alexandre Bury 2017-03-25 14:50:52 -07:00
parent 2cd2787119
commit 017bb21710
8 changed files with 86 additions and 6 deletions

View File

@ -392,6 +392,8 @@ impl Cursive {
self.screen_mut().find(sel) self.screen_mut().find(sel)
} }
/// Tries to find the view identified by the given id.
///
/// Convenient method to use `find` with a `view::Selector::Id`. /// Convenient method to use `find` with a `view::Selector::Id`.
/// ///
/// # Examples /// # Examples
@ -417,6 +419,18 @@ impl Cursive {
self.find(&view::Selector::Id(id)) self.find(&view::Selector::Id(id))
} }
/// Moves the focus to the view identified by `id`.
///
/// Convenient method to call `focus` with a `view::Selector::Id`.
pub fn focus_id(&mut self, id: &str) -> Result<(), ()> {
self.focus(&view::Selector::Id(id))
}
/// Moves the focus to the view identified by `sel`.
pub fn focus(&mut self, sel: &view::Selector) -> Result<(), ()> {
self.screen_mut().focus_view(sel)
}
/// Adds a global callback. /// Adds a global callback.
/// ///
/// Will be triggered on the given key press when no view catches it. /// Will be triggered on the given key press when no view catches it.

View File

@ -113,7 +113,7 @@ pub trait View {
/// Draws the view with the given printer (includes bounds) and focus. /// Draws the view with the given printer (includes bounds) and focus.
fn draw(&self, printer: &Printer); fn draw(&self, printer: &Printer);
/// Finds the view pointed to by the given path. /// Finds the view identified by the given selector.
/// ///
/// See [`Finder::find`] for a nicer interface, implemented for all views. /// See [`Finder::find`] for a nicer interface, implemented for all views.
/// ///
@ -126,6 +126,13 @@ pub trait View {
None None
} }
/// Moves the focus to the view identified by the given selector.
///
/// Returns `Ok(())` if the view was found and selected.
fn focus_view(&mut self, &Selector) -> Result<(), ()> {
Err(())
}
/// This view is offered focus. Will it take it? /// This view is offered focus. Will it take it?
/// ///
/// `source` indicates where the focus comes from. /// `source` indicates where the focus comes from.

View File

@ -55,6 +55,11 @@ pub trait ViewWrapper {
self.get_view_mut().find_any(selector) self.get_view_mut().find_any(selector)
} }
/// Wraps the `focus_view` method.
fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
self.get_view_mut().focus_view(selector)
}
/// Wraps the `needs_relayout` method. /// Wraps the `needs_relayout` method.
fn wrap_needs_relayout(&self) -> bool { fn wrap_needs_relayout(&self) -> bool {
self.get_view().needs_relayout() self.get_view().needs_relayout()
@ -89,6 +94,10 @@ impl<T: ViewWrapper> View for T {
fn needs_relayout(&self) -> bool { fn needs_relayout(&self) -> bool {
self.wrap_needs_relayout() self.wrap_needs_relayout()
} }
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
self.wrap_focus_view(selector)
}
} }
/// Convenient macro to implement the [`ViewWrapper`] trait. /// Convenient macro to implement the [`ViewWrapper`] trait.

View File

@ -402,4 +402,8 @@ impl View for Dialog {
fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> { fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> {
self.content.find_any(selector) self.content.find_any(selector)
} }
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
self.content.focus_view(selector)
}
} }

View File

@ -27,4 +27,11 @@ impl<T: View + Any> ViewWrapper for IdView<T> {
s => self.view.find_any(s), s => self.view.find_any(s),
} }
} }
fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
match selector {
&Selector::Id(id) if id == self.id => Ok(()),
s => self.view.focus_view(s),
}
}
} }

View File

@ -401,4 +401,15 @@ impl View for LinearLayout {
.filter_map(|c| c.view.find_any(selector)) .filter_map(|c| c.view.find_any(selector))
.next() .next()
} }
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(())
}
} }

View File

@ -118,7 +118,10 @@ impl ListView {
direction::Relative::Front => { direction::Relative::Front => {
let start = if from_focus { self.focus } else { 0 }; let start = if from_focus { self.focus } else { 0 };
Box::new(self.children.iter_mut().enumerate().skip(start)) Box::new(self.children
.iter_mut()
.enumerate()
.skip(start))
} }
direction::Relative::Back => { direction::Relative::Back => {
let end = if from_focus { let end = if from_focus {
@ -296,10 +299,11 @@ impl View for ListView {
fn take_focus(&mut self, source: direction::Direction) -> bool { fn take_focus(&mut self, source: direction::Direction) -> bool {
let rel = source.relative(direction::Orientation::Vertical); let rel = source.relative(direction::Orientation::Vertical);
let i = if let Some(i) = self.iter_mut(rel.is_none(), let i = if let Some(i) =
rel.unwrap_or(direction::Relative::Front)) self.iter_mut(rel.is_none(),
.filter_map(|p| try_focus(p, source)) rel.unwrap_or(direction::Relative::Front))
.next() { .filter_map(|p| try_focus(p, source))
.next() {
i i
} else { } else {
// No one wants to be in focus // No one wants to be in focus
@ -317,4 +321,18 @@ impl View for ListView {
.filter_map(|v| v.find_any(selector)) .filter_map(|v| v.find_any(selector))
.next() .next()
} }
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
if let Some(i) = self.children
.iter_mut()
.enumerate()
.filter_map(|(i, v)| v.view().map(|v| (i, v)))
.filter_map(|(i, v)| v.focus_view(selector).ok().map(|_| i))
.next() {
self.focus = i;
Ok(())
} else {
Err(())
}
}
} }

View File

@ -186,4 +186,14 @@ impl View for StackView {
.filter_map(|l| l.view.find_any(selector)) .filter_map(|l| l.view.find_any(selector))
.next() .next()
} }
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
for layer in &mut self.layers {
if layer.view.focus_view(selector).is_ok() {
return Ok(());
}
}
Err(())
}
} }