feat: Add SelectView::select_{up,down}

This commit is contained in:
Alexandre Bury 2017-08-23 16:48:54 -07:00
parent 6bb3e88c2e
commit da6a92f508

View File

@ -132,7 +132,8 @@ impl<T: 'static> SelectView<T> {
/// Sets a callback to be used when an item is selected. /// Sets a callback to be used when an item is selected.
pub fn set_on_select<F>(&mut self, cb: F) pub fn set_on_select<F>(&mut self, cb: F)
where F: Fn(&mut Cursive, &T) + 'static where
F: Fn(&mut Cursive, &T) + 'static,
{ {
self.on_select = Some(Rc::new(cb)); self.on_select = Some(Rc::new(cb));
} }
@ -141,7 +142,8 @@ impl<T: 'static> SelectView<T> {
/// ///
/// Chainable variant. /// Chainable variant.
pub fn on_select<F>(self, cb: F) -> Self pub fn on_select<F>(self, cb: F) -> Self
where F: Fn(&mut Cursive, &T) + 'static where
F: Fn(&mut Cursive, &T) + 'static,
{ {
self.with(|s| s.set_on_select(cb)) self.with(|s| s.set_on_select(cb))
} }
@ -152,8 +154,9 @@ impl<T: 'static> SelectView<T> {
/// ///
/// Here, `V` can be `T` itself, or a type that can be borrowed from `T`. /// Here, `V` can be `T` itself, or a type that can be borrowed from `T`.
pub fn set_on_submit<F, V: ?Sized>(&mut self, cb: F) pub fn set_on_submit<F, V: ?Sized>(&mut self, cb: F)
where F: Fn(&mut Cursive, &V) + 'static, where
T: Borrow<V> F: Fn(&mut Cursive, &V) + 'static,
T: Borrow<V>,
{ {
self.on_submit = Some(Rc::new(move |s, t| cb(s, t.borrow()))); self.on_submit = Some(Rc::new(move |s, t| cb(s, t.borrow())));
} }
@ -164,8 +167,9 @@ impl<T: 'static> SelectView<T> {
/// ///
/// Chainable variant. /// Chainable variant.
pub fn on_submit<F, V: ?Sized>(self, cb: F) -> Self pub fn on_submit<F, V: ?Sized>(self, cb: F) -> Self
where F: Fn(&mut Cursive, &V) + 'static, where
T: Borrow<V> F: Fn(&mut Cursive, &V) + 'static,
T: Borrow<V>,
{ {
self.with(|s| s.set_on_submit(cb)) self.with(|s| s.set_on_submit(cb))
} }
@ -227,8 +231,9 @@ impl<T: 'static> SelectView<T> {
/// Adds all items from from an iterator. /// Adds all items from from an iterator.
pub fn add_all<S, I>(&mut self, iter: I) pub fn add_all<S, I>(&mut self, iter: I)
where S: Into<String>, where
I: IntoIterator<Item = (S, T)> S: Into<String>,
I: IntoIterator<Item = (S, T)>,
{ {
for (s, t) in iter { for (s, t) in iter {
self.add_item(s, t); self.add_item(s, t);
@ -239,8 +244,9 @@ impl<T: 'static> SelectView<T> {
/// ///
/// Chainable variant. /// Chainable variant.
pub fn with_all<S, I>(self, iter: I) -> Self pub fn with_all<S, I>(self, iter: I) -> Self
where S: Into<String>, where
I: IntoIterator<Item = (S, T)> S: Into<String>,
I: IntoIterator<Item = (S, T)>,
{ {
self.with(|s| s.add_all(iter)) self.with(|s| s.add_all(iter))
} }
@ -288,11 +294,27 @@ impl<T: 'static> SelectView<T> {
self.scrollbase.scroll_to(i); self.scrollbase.scroll_to(i);
} }
fn focus_up(&mut self, n: usize) { /// Moves the selection up by the given number of rows.
pub fn select_up(&mut self, n: usize) {
self.focus_up(n);
let focus = self.focus(); let focus = self.focus();
self.focus.set(focus.saturating_sub(n)); self.scrollbase.scroll_to(focus);
} }
/// Moves the selection down by the given number of rows.
pub fn select_down(&mut self, n: usize) {
self.focus_down(n);
let focus = self.focus();
self.scrollbase.scroll_to(focus);
}
// Low-level focus change. Does not fix scrollbase.
fn focus_up(&mut self, n: usize) {
let focus = self.focus().saturating_sub(n);
self.focus.set(focus);
}
// Low-level focus change. Does not fix scrollbase.
fn focus_down(&mut self, n: usize) { fn focus_down(&mut self, n: usize) {
let focus = min(self.focus() + n, self.items.len().saturating_sub(1)); let focus = min(self.focus() + n, self.items.len().saturating_sub(1));
self.focus.set(focus); self.focus.set(focus);
@ -321,8 +343,9 @@ impl SelectView<String> {
/// select_view.add_all_str(vec!["a", "b", "c"]); /// select_view.add_all_str(vec!["a", "b", "c"]);
/// ``` /// ```
pub fn add_all_str<S, I>(&mut self, iter: I) pub fn add_all_str<S, I>(&mut self, iter: I)
where S: Into<String>, where
I: IntoIterator<Item = S> S: Into<String>,
I: IntoIterator<Item = S>,
{ {
for s in iter { for s in iter {
self.add_item_str(s); self.add_item_str(s);
@ -333,8 +356,9 @@ impl SelectView<String> {
/// ///
/// Chainable variant. /// Chainable variant.
pub fn with_all_str<S, I>(self, iter: I) -> Self pub fn with_all_str<S, I>(self, iter: I) -> Self
where S: Into<String>, where
I: IntoIterator<Item = S> S: Into<String>,
I: IntoIterator<Item = S>,
{ {
self.with(|s| s.add_all_str(iter)) self.with(|s| s.add_all_str(iter))
} }
@ -372,7 +396,6 @@ impl<T: 'static> View for SelectView<T> {
printer.print((offset, 0), label); printer.print((offset, 0), label);
}); });
} else { } else {
let h = self.items.len(); let h = self.items.len();
let offset = self.align.v.get_offset(h, printer.size.y); let offset = self.align.v.get_offset(h, printer.size.y);
let printer = let printer =
@ -465,9 +488,10 @@ impl<T: 'static> View for SelectView<T> {
let current_offset = s.screen().offset(); let current_offset = s.screen().offset();
let offset = offset.signed() - current_offset; let offset = offset.signed() - current_offset;
// And finally, put the view in view! // And finally, put the view in view!
s.screen_mut().add_layer_at(Position::parent(offset), s.screen_mut().add_layer_at(
MenuPopup::new(tree) Position::parent(offset),
.focus(focus)); MenuPopup::new(tree).focus(focus),
);
}) })
} }
_ => EventResult::Ignored, _ => EventResult::Ignored,
@ -475,21 +499,24 @@ impl<T: 'static> View for SelectView<T> {
} else { } else {
match event { match event {
Event::Key(Key::Up) if self.focus() > 0 => self.focus_up(1), Event::Key(Key::Up) if self.focus() > 0 => self.focus_up(1),
Event::Key(Key::Down) if self.focus() + 1 < Event::Key(Key::Down)
self.items.len() => { if self.focus() + 1 < self.items.len() =>
{
self.focus_down(1) self.focus_down(1)
} }
Event::Key(Key::PageUp) => self.focus_up(10), Event::Key(Key::PageUp) => self.focus_up(10),
Event::Key(Key::PageDown) => self.focus_down(10), Event::Key(Key::PageDown) => self.focus_down(10),
Event::Key(Key::Home) => self.focus.set(0), Event::Key(Key::Home) => self.focus.set(0),
Event::Key(Key::End) => self.focus.set(self.items.len().saturating_sub(1)), Event::Key(Key::End) => {
self.focus.set(self.items.len().saturating_sub(1))
}
Event::Key(Key::Enter) if self.on_submit.is_some() => { Event::Key(Key::Enter) if self.on_submit.is_some() => {
let cb = self.on_submit.clone().unwrap(); let cb = self.on_submit.clone().unwrap();
let v = self.selection(); let v = self.selection();
// We return a Callback Rc<|s| cb(s, &*v)> // We return a Callback Rc<|s| cb(s, &*v)>
return EventResult::Consumed(Some(Callback::from_fn(move |s| { return EventResult::Consumed(
cb(s, &v) Some(Callback::from_fn(move |s| cb(s, &v))),
}))); );
} }
Event::Char(c) => { Event::Char(c) => {
// Starting from the current focus, // Starting from the current focus,
@ -498,10 +525,10 @@ impl<T: 'static> View for SelectView<T> {
// the list when we reach the end. // the list when we reach the end.
// This is achieved by chaining twice the iterator // This is achieved by chaining twice the iterator
let iter = self.items.iter().chain(self.items.iter()); let iter = self.items.iter().chain(self.items.iter());
if let Some((i, _)) = if let Some((i, _)) = iter.enumerate()
iter.enumerate()
.skip(self.focus() + 1) .skip(self.focus() + 1)
.find(|&(_, item)| item.label.starts_with(c)) { .find(|&(_, item)| item.label.starts_with(c))
{
// Apply modulo in case we have a hit // Apply modulo in case we have a hit
// from the chained iterator // from the chained iterator
self.focus.set(i % self.items.len()); self.focus.set(i % self.items.len());