Return view on pop_layer

Callbacks now often allow (and ignore) a return type.
This commit is contained in:
Alexandre Bury 2017-12-15 08:45:14 +01:00
parent 1b7170e308
commit bd9b6a695b
8 changed files with 75 additions and 50 deletions

View File

@ -394,9 +394,10 @@ impl Cursive {
} }
/// Convenient method to remove a layer from the current screen. /// Convenient method to remove a layer from the current screen.
pub fn pop_layer(&mut self) { pub fn pop_layer(&mut self) -> Option<Box<View>> {
self.screen_mut().pop_layer(); let result = self.screen_mut().pop_layer();
self.clear(); self.clear();
result
} }
// Handles a key event when it was ignored by the current view // Handles a key event when it was ignored by the current view

View File

@ -27,8 +27,13 @@ pub struct Callback(Rc<Box<Fn(&mut Cursive)>>);
impl Callback { impl Callback {
/// Wraps the given function into a `Callback` object. /// Wraps the given function into a `Callback` object.
pub fn from_fn<F: Fn(&mut Cursive) + 'static>(f: F) -> Self { pub fn from_fn<F, R>(f: F) -> Self
Callback(Rc::new(Box::new(f))) where
F: 'static + Fn(&mut Cursive) -> R,
{
Callback(Rc::new(Box::new(move |siv| {
f(siv);
})))
} }
} }
@ -68,7 +73,10 @@ pub enum EventResult {
impl EventResult { impl EventResult {
/// Convenient method to create `Consumed(Some(f))` /// Convenient method to create `Consumed(Some(f))`
pub fn with_cb<F: 'static + Fn(&mut Cursive)>(f: F) -> Self { pub fn with_cb<F, R>(f: F) -> Self
where
F: 'static + Fn(&mut Cursive) -> R,
{
EventResult::Consumed(Some(Callback::from_fn(f))) EventResult::Consumed(Some(Callback::from_fn(f)))
} }
@ -245,9 +253,9 @@ impl MouseEvent {
/// Returns `None` if `self` is `WheelUp` or `WheelDown`. /// Returns `None` if `self` is `WheelUp` or `WheelDown`.
pub fn button(&self) -> Option<MouseButton> { pub fn button(&self) -> Option<MouseButton> {
match *self { match *self {
MouseEvent::Press(btn) | MouseEvent::Press(btn)
MouseEvent::Release(btn) | | MouseEvent::Release(btn)
MouseEvent::Hold(btn) => Some(btn), | MouseEvent::Hold(btn) => Some(btn),
_ => None, _ => None,
} }
} }
@ -257,9 +265,9 @@ impl MouseEvent {
/// This includes `Press`, `WheelUp` and `WheelDown`. /// This includes `Press`, `WheelUp` and `WheelDown`.
pub fn grabs_focus(self) -> bool { pub fn grabs_focus(self) -> bool {
match self { match self {
MouseEvent::Press(_) | MouseEvent::Press(_)
MouseEvent::WheelUp | | MouseEvent::WheelUp
MouseEvent::WheelDown => true, | MouseEvent::WheelDown => true,
_ => false, _ => false,
} }
} }

View File

@ -27,18 +27,18 @@ pub struct Button {
impl Button { impl Button {
/// Creates a new button with the given content and callback. /// Creates a new button with the given content and callback.
pub fn new<F, S: Into<String>>(label: S, cb: F) -> Self pub fn new<F, R, S: Into<String>>(label: S, cb: F) -> Self
where where
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
let label = label.into(); let label = label.into();
Self::new_raw(format!("<{}>", label), cb) Self::new_raw(format!("<{}>", label), cb)
} }
/// Creates a new button without angle brackets. /// Creates a new button without angle brackets.
pub fn new_raw<F, S: Into<String>>(label: S, cb: F) -> Self pub fn new_raw<F, R, S: Into<String>>(label: S, cb: F) -> Self
where where
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
Button { Button {
label: label.into(), label: label.into(),

View File

@ -25,9 +25,9 @@ struct ChildButton {
} }
impl ChildButton { impl ChildButton {
pub fn new<F, S: Into<String>>(label: S, cb: F) -> Self pub fn new<F, R, S: Into<String>>(label: S, cb: F) -> Self
where where
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
ChildButton { ChildButton {
button: SizedView::new(Button::new(label, cb)), button: SizedView::new(Button::new(label, cb)),
@ -125,9 +125,9 @@ impl Dialog {
/// Adds a button to the dialog with the given label and callback. /// Adds a button to the dialog with the given label and callback.
/// ///
/// Consumes and returns self for easy chaining. /// Consumes and returns self for easy chaining.
pub fn button<F, S: Into<String>>(mut self, label: S, cb: F) -> Self pub fn button<F, R, S: Into<String>>(mut self, label: S, cb: F) -> Self
where where
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
self.buttons.push(ChildButton::new(label, cb)); self.buttons.push(ChildButton::new(label, cb));
@ -158,7 +158,7 @@ impl Dialog {
/// Shortcut method to add a button that will dismiss the dialog. /// Shortcut method to add a button that will dismiss the dialog.
pub fn dismiss_button<S: Into<String>>(self, label: S) -> Self { pub fn dismiss_button<S: Into<String>>(self, label: S) -> Self {
self.button(label, |s| s.screen_mut().pop_layer()) self.button(label, |s| s.pop_layer())
} }
/// Sets the title of the dialog. /// Sets the title of the dialog.
@ -226,9 +226,9 @@ impl Dialog {
) { ) {
EventResult::Ignored if !self.buttons.is_empty() => { EventResult::Ignored if !self.buttons.is_empty() => {
match event { match event {
Event::Key(Key::Down) | Event::Key(Key::Down)
Event::Key(Key::Tab) | | Event::Key(Key::Tab)
Event::Shift(Key::Tab) => { | Event::Shift(Key::Tab) => {
// Default to leftmost button when going down. // Default to leftmost button when going down.
self.focus = Focus::Button(0); self.focus = Focus::Button(0);
EventResult::Consumed(None) EventResult::Consumed(None)
@ -365,7 +365,9 @@ impl Dialog {
return; return;
} }
let spacing = 3; //minimum distance to borders let spacing = 3; //minimum distance to borders
let x = spacing + self.title_position.get_offset(len, printer.size.x - 2 * spacing); let x = spacing
+ self.title_position
.get_offset(len, printer.size.x - 2 * spacing);
printer.with_high_border(false, |printer| { printer.with_high_border(false, |printer| {
printer.print((x - 2, 0), ""); printer.print((x - 2, 0), "");
printer.print((x + len, 0), ""); printer.print((x + len, 0), "");

View File

@ -1,5 +1,3 @@
use Cursive; use Cursive;
use Printer; use Printer;
use With; use With;
@ -376,8 +374,8 @@ impl View for MenuPopup {
} }
} }
} }
Event::Key(Key::Esc) | Event::Key(Key::Esc)
Event::Mouse { | Event::Mouse {
event: MouseEvent::Press(_), event: MouseEvent::Press(_),
.. ..
} => { } => {

View File

@ -18,7 +18,7 @@ use view::{View, ViewWrapper};
/// ///
/// "Inner" callbacks ([`on_event_inner`] and [`on_pre_event_inner`]) are given /// "Inner" callbacks ([`on_event_inner`] and [`on_pre_event_inner`]) are given
/// a reference to the inner wrapped view (but not to the `Cursive` root). They /// a reference to the inner wrapped view (but not to the `Cursive` root). They
/// can then return another callback, taking only a `&mut Cursive` root as /// can then return another callback, taking only a `&mut Cursive` root as
/// argument. /// argument.
/// ///
/// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first /// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first
@ -77,10 +77,10 @@ impl<T: View> OnEventView<T> {
/// Registers a callback when the given event is ignored by the child. /// Registers a callback when the given event is ignored by the child.
/// ///
/// Chainable variant. /// Chainable variant.
pub fn on_event<F, E>(self, event: E, cb: F) -> Self pub fn on_event<F, R, E>(self, event: E, cb: F) -> Self
where where
E: Into<Event>, E: Into<Event>,
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
self.with(|s| s.set_on_event(event, cb)) self.with(|s| s.set_on_event(event, cb))
} }
@ -90,10 +90,10 @@ impl<T: View> OnEventView<T> {
/// The child will never receive this event. /// The child will never receive this event.
/// ///
/// Chainable variant. /// Chainable variant.
pub fn on_pre_event<F, E>(self, event: E, cb: F) -> Self pub fn on_pre_event<F, R, E>(self, event: E, cb: F) -> Self
where where
E: Into<Event>, E: Into<Event>,
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
self.with(|s| s.set_on_pre_event(event, cb)) self.with(|s| s.set_on_pre_event(event, cb))
} }
@ -132,10 +132,10 @@ impl<T: View> OnEventView<T> {
} }
/// Registers a callback when the given event is ignored by the child. /// Registers a callback when the given event is ignored by the child.
pub fn set_on_event<F, E>(&mut self, event: E, cb: F) pub fn set_on_event<F, R, E>(&mut self, event: E, cb: F)
where where
E: Into<Event>, E: Into<Event>,
F: Fn(&mut Cursive) + 'static, F: Fn(&mut Cursive) -> R + 'static,
{ {
let cb = Callback::from_fn(cb); let cb = Callback::from_fn(cb);
let action = let action =
@ -147,12 +147,13 @@ impl<T: View> OnEventView<T> {
/// Registers a callback when the given event is received. /// Registers a callback when the given event is received.
/// ///
/// The child will never receive this event. /// The child will never receive this event.
pub fn set_on_pre_event<F, E>(&mut self, event: E, cb: F) pub fn set_on_pre_event<F, R, E>(&mut self, event: E, cb: F)
where where
E: Into<Event>, E: Into<Event>,
F: Fn(&mut Cursive) + 'static, F: 'static + Fn(&mut Cursive) -> R,
{ {
let cb = Callback::from_fn(cb); let cb = Callback::from_fn(cb);
// We want to clone the Callback every time we call the closure
let action = let action =
move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone()))); move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

View File

@ -152,12 +152,14 @@ impl<T: 'static> SelectView<T> {
/// The item currently selected will be given to the callback. /// The item currently selected will be given to the callback.
/// ///
/// 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, R, V: ?Sized>(&mut self, cb: F)
where where
F: Fn(&mut Cursive, &V) + 'static, F: 'static + Fn(&mut Cursive, &V) -> R,
T: Borrow<V>, 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());
}));
} }
/// Sets a callback to be used when `<Enter>` is pressed. /// Sets a callback to be used when `<Enter>` is pressed.

View File

@ -6,7 +6,7 @@ use std::any::Any;
use std::ops::Deref; use std::ops::Deref;
use theme::ColorStyle; use theme::ColorStyle;
use vec::Vec2; use vec::Vec2;
use view::{Offset, Position, Selector, View}; use view::{Offset, Position, Selector, View, ViewWrapper};
use views::{Layer, ShadowView}; use views::{Layer, ShadowView};
/// Simple stack of views. /// Simple stack of views.
@ -47,9 +47,20 @@ enum ChildWrapper<T: View> {
Plain(Layer<T>), Plain(Layer<T>),
} }
// TODO: use macros to make this less ugly? impl<T: View> ChildWrapper<T> {
impl <T: View> View for ChildWrapper<T> { fn unwrap(self) -> T {
match self {
// ShadowView::into_inner and Layer::into_inner can never fail.
ChildWrapper::Shadow(shadow) => {
shadow.into_inner().ok().unwrap().into_inner().ok().unwrap()
}
ChildWrapper::Plain(layer) => layer.into_inner().ok().unwrap(),
}
}
}
// TODO: use macros to make this less ugly?
impl<T: View> View for ChildWrapper<T> {
fn draw(&self, printer: &Printer) { fn draw(&self, printer: &Printer) {
match *self { match *self {
ChildWrapper::Shadow(ref v) => v.draw(printer), ChildWrapper::Shadow(ref v) => v.draw(printer),
@ -86,12 +97,15 @@ impl <T: View> View for ChildWrapper<T> {
} }
fn call_on_any<'a>( fn call_on_any<'a>(
&mut self, selector: &Selector, &mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
callback: Box<FnMut(&mut Any) + 'a>,
) { ) {
match *self { match *self {
ChildWrapper::Shadow(ref mut v) => v.call_on_any(selector, callback), ChildWrapper::Shadow(ref mut v) => {
ChildWrapper::Plain(ref mut v) => v.call_on_any(selector, callback), v.call_on_any(selector, callback)
}
ChildWrapper::Plain(ref mut v) => {
v.call_on_any(selector, callback)
}
} }
} }
@ -101,7 +115,6 @@ impl <T: View> View for ChildWrapper<T> {
ChildWrapper::Plain(ref mut v) => v.focus_view(selector), ChildWrapper::Plain(ref mut v) => v.focus_view(selector),
} }
} }
} }
struct Child { struct Child {
@ -201,8 +214,8 @@ impl StackView {
} }
/// Remove the top-most layer. /// Remove the top-most layer.
pub fn pop_layer(&mut self) { pub fn pop_layer(&mut self) -> Option<Box<View>> {
self.layers.pop(); self.layers.pop().map(|child| child.view.unwrap())
} }
/// Computes the offset of the current top view. /// Computes the offset of the current top view.