2016-03-15 22:37:57 +00:00
|
|
|
use Cursive;
|
2017-08-23 23:43:17 +00:00
|
|
|
use With;
|
2016-07-11 01:27:26 +00:00
|
|
|
use event::{Callback, Event, EventResult};
|
2016-10-02 22:22:29 +00:00
|
|
|
use std::collections::HashMap;
|
2017-08-23 23:43:17 +00:00
|
|
|
use std::rc::Rc;
|
2016-07-28 23:36:01 +00:00
|
|
|
use view::{View, ViewWrapper};
|
2015-05-16 00:56:38 +00:00
|
|
|
|
|
|
|
/// A simple wrapper view that catches some ignored event from its child.
|
|
|
|
///
|
2016-07-21 05:08:06 +00:00
|
|
|
/// If the event doesn't have a corresponding callback, it will stay ignored.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
2016-09-29 05:45:27 +00:00
|
|
|
/// # use cursive::event;;
|
2017-06-12 23:39:12 +00:00
|
|
|
/// # use cursive::views::{OnEventView, TextView};
|
|
|
|
/// let view = OnEventView::new(TextView::new("This view has an event!"))
|
|
|
|
/// .on_event('q', |s| s.quit())
|
|
|
|
/// .on_event(event::Key::Esc, |s| s.quit());
|
2016-07-21 05:08:06 +00:00
|
|
|
/// ```
|
2017-06-12 23:39:12 +00:00
|
|
|
pub struct OnEventView<T: View> {
|
2017-08-23 23:43:17 +00:00
|
|
|
inner: T,
|
|
|
|
callbacks: HashMap<Event, Action<T>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
type InnerCallback<T> = Rc<Box<Fn(&mut T) -> Option<EventResult>>>;
|
|
|
|
|
|
|
|
struct Action<T> {
|
|
|
|
phase: TriggerPhase,
|
|
|
|
callback: InnerCallback<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Clone for Action<T> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Action {
|
|
|
|
phase: self.phase.clone(),
|
|
|
|
callback: self.callback.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Clone)]
|
|
|
|
enum TriggerPhase {
|
|
|
|
BeforeChild,
|
|
|
|
AfterChild,
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-12 23:39:12 +00:00
|
|
|
impl<T: View> OnEventView<T> {
|
|
|
|
/// Wraps the given view in a new OnEventView.
|
2016-09-20 00:11:00 +00:00
|
|
|
pub fn new(view: T) -> Self {
|
2017-06-12 23:39:12 +00:00
|
|
|
OnEventView {
|
2017-08-23 23:43:17 +00:00
|
|
|
inner: view,
|
2015-05-16 00:56:38 +00:00
|
|
|
callbacks: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 23:39:12 +00:00
|
|
|
/// Registers a callback when the given event is ignored by the child.
|
|
|
|
///
|
|
|
|
/// Chainable variant.
|
2017-08-23 23:43:17 +00:00
|
|
|
pub fn on_event<F, E>(self, event: E, cb: F) -> Self
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut Cursive) + 'static,
|
2015-05-16 00:56:38 +00:00
|
|
|
{
|
2017-06-12 23:39:12 +00:00
|
|
|
self.with(|s| s.set_on_event(event, cb))
|
|
|
|
}
|
2015-05-16 00:56:38 +00:00
|
|
|
|
2017-08-23 23:43:17 +00:00
|
|
|
/// Registers a callback when the given event is received.
|
|
|
|
///
|
|
|
|
/// The child will never receive this event.
|
|
|
|
///
|
|
|
|
/// Chainable variant.
|
|
|
|
pub fn on_pre_event<F, E>(self, event: E, cb: F) -> Self
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut Cursive) + 'static,
|
|
|
|
{
|
|
|
|
self.with(|s| s.set_on_pre_event(event, cb))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers a callback when the given event is received.
|
|
|
|
///
|
|
|
|
/// The given callback will be run before the child view sees the event.
|
|
|
|
/// If the result is `None`, then the child view is given the event as usual.
|
|
|
|
/// Otherwise, it bypasses the child view and directly processes the result.
|
|
|
|
///
|
|
|
|
/// Chainable variant.
|
|
|
|
pub fn on_pre_event_inner<F, E>(self, event: E, cb: F) -> Self
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
|
|
|
{
|
|
|
|
self.with(|s| s.set_on_pre_event_inner(event, cb))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers a callback when the given event is ignored by the child.
|
|
|
|
///
|
|
|
|
/// If the child view ignores the event, `cb` will be called with the
|
|
|
|
/// child view as argument.
|
|
|
|
/// If the result is not `None`, it will be processed as well.
|
|
|
|
///
|
|
|
|
/// Chainable variant.
|
|
|
|
pub fn on_event_inner<F, E>(self, event: E, cb: F) -> Self
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
|
|
|
{
|
|
|
|
self.with(|s| s.set_on_event_inner(event, cb))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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)
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut Cursive) + 'static,
|
|
|
|
{
|
|
|
|
let cb = Callback::from_fn(cb);
|
|
|
|
let action =
|
|
|
|
move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));
|
|
|
|
|
|
|
|
self.set_on_event_inner(event, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers a callback when the given event is received.
|
|
|
|
///
|
|
|
|
/// The child will never receive this event.
|
|
|
|
pub fn set_on_pre_event<F, E>(&mut self, event: E, cb: F)
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut Cursive) + 'static,
|
|
|
|
{
|
|
|
|
let cb = Callback::from_fn(cb);
|
|
|
|
let action =
|
|
|
|
move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));
|
|
|
|
|
|
|
|
self.set_on_pre_event_inner(event, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers a callback when the given event is received.
|
|
|
|
///
|
|
|
|
/// The given callback will be run before the child view sees the event.
|
|
|
|
/// If the result is `None`, then the child view is given the event as usual.
|
|
|
|
/// Otherwise, it bypasses the child view and directly processes the result.
|
|
|
|
pub fn set_on_pre_event_inner<F, E>(&mut self, event: E, cb: F)
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
|
|
|
{
|
|
|
|
self.callbacks.insert(
|
|
|
|
event.into(),
|
|
|
|
Action {
|
|
|
|
phase: TriggerPhase::BeforeChild,
|
|
|
|
callback: Rc::new(Box::new(cb)),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-06-12 23:39:12 +00:00
|
|
|
/// Registers a callback when the given event is ignored by the child.
|
2017-08-23 23:43:17 +00:00
|
|
|
///
|
|
|
|
/// If the child view ignores the event, `cb` will be called with the
|
|
|
|
/// child view as argument.
|
|
|
|
/// If the result is not `None`, it will be processed as well.
|
|
|
|
pub fn set_on_event_inner<F, E>(&mut self, event: E, cb: F)
|
|
|
|
where
|
|
|
|
E: Into<Event>,
|
|
|
|
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
2017-06-12 23:39:12 +00:00
|
|
|
{
|
2017-08-23 23:43:17 +00:00
|
|
|
self.callbacks.insert(
|
|
|
|
event.into(),
|
|
|
|
Action {
|
|
|
|
phase: TriggerPhase::AfterChild,
|
|
|
|
callback: Rc::new(Box::new(cb)),
|
|
|
|
},
|
|
|
|
);
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 23:39:12 +00:00
|
|
|
impl<T: View> ViewWrapper for OnEventView<T> {
|
2017-08-23 23:43:17 +00:00
|
|
|
wrap_impl!(self.inner: T);
|
2015-05-19 22:54:11 +00:00
|
|
|
|
2015-05-28 01:04:33 +00:00
|
|
|
fn wrap_on_event(&mut self, event: Event) -> EventResult {
|
2017-08-23 23:43:17 +00:00
|
|
|
let action = self.callbacks.get(&event).cloned();
|
|
|
|
let pre_child = action
|
|
|
|
.as_ref()
|
|
|
|
.map(|a| a.phase == TriggerPhase::BeforeChild)
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
|
|
|
if pre_child {
|
|
|
|
action
|
|
|
|
.and_then(|a| (*a.callback)(&mut self.inner))
|
|
|
|
.unwrap_or_else(|| self.inner.on_event(event))
|
|
|
|
} else {
|
|
|
|
self.inner.on_event(event).or_else(|| {
|
|
|
|
action
|
|
|
|
.and_then(|a| (*a.callback)(&mut self.inner))
|
|
|
|
.unwrap_or(EventResult::Ignored)
|
|
|
|
})
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|