cursive/src/views/on_event_view.rs

254 lines
8.3 KiB
Rust
Raw Normal View History

2018-11-09 18:40:06 +00:00
use event::{Callback, Event, EventResult, EventTrigger};
use std::rc::Rc;
2016-07-28 23:36:01 +00:00
use view::{View, ViewWrapper};
2018-06-11 06:29:10 +00:00
use Cursive;
use With;
2017-12-08 00:47:56 +00:00
/// A wrapper view that can react to events.
///
2017-12-08 00:47:56 +00:00
/// This view registers a set of callbacks tied to specific events, to be run
/// in certain conditions.
///
2018-11-09 18:40:06 +00:00
/// * Some callbacks are called only for events ignored by the wrapped view.
///
2017-12-08 00:47:56 +00:00
/// (those registered by [`on_event`] or [`on_event_inner`])
/// * Others are processed first, and can control whether the child view should
/// be given the event (those registered by [`on_pre_event`] or
/// [`on_pre_event_inner`]).
///
/// "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
/// can then return another callback, taking only a `&mut Cursive` root as
2017-12-08 00:47:56 +00:00
/// argument.
///
/// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first
/// phase and are only called with a `&mut Cursive`.
///
/// [`on_event`]: struct.OnEventView.html#method.on_event
/// [`on_pre_event`]: struct.OnEventView.html#method.on_pre_event
/// [`on_event_inner`]: struct.OnEventView.html#method.on_event_inner
/// [`on_pre_event_inner`]: struct.OnEventView.html#method.on_pre_event_inner
2016-07-21 05:08:06 +00:00
///
/// # Examples
///
/// ```
/// # 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> {
view: T,
2018-11-09 18:40:06 +00:00
callbacks: Vec<(EventTrigger, Action<T>)>,
}
2018-11-09 18:40:06 +00:00
type InnerCallback<T> = Rc<Box<Fn(&mut T, &Event) -> 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(),
2017-10-13 18:22:02 +00:00
callback: Rc::clone(&self.callback),
}
}
}
#[derive(PartialEq, Clone)]
enum TriggerPhase {
BeforeChild,
AfterChild,
}
2017-06-12 23:39:12 +00:00
impl<T: View> OnEventView<T> {
/// Wraps the given view in a new OnEventView.
pub fn new(view: T) -> Self {
2017-06-12 23:39:12 +00:00
OnEventView {
2018-04-10 18:53:25 +00:00
view,
2018-11-09 18:40:06 +00:00
callbacks: Vec::new(),
}
}
2017-06-12 23:39:12 +00:00
/// Registers a callback when the given event is ignored by the child.
///
/// Chainable variant.
2018-11-09 18:40:06 +00:00
pub fn on_event<F, E>(self, trigger: E, cb: F) -> Self
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: 'static + Fn(&mut Cursive),
{
2018-11-09 18:40:06 +00:00
self.with(|s| s.set_on_event(trigger, cb))
2017-06-12 23:39:12 +00:00
}
/// Registers a callback when the given event is received.
///
/// The child will never receive this event.
///
/// Chainable variant.
2018-11-09 18:40:06 +00:00
pub fn on_pre_event<F, E>(self, trigger: E, cb: F) -> Self
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: 'static + Fn(&mut Cursive),
{
2018-11-09 18:40:06 +00:00
self.with(|s| s.set_on_pre_event(trigger, cb))
}
/// Registers a callback when the given event is received.
///
/// The given callback will be run before the child view sees the event.
2017-12-08 00:47:56 +00:00
///
2017-10-15 04:18:50 +00:00
/// * 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.
2018-11-09 18:40:06 +00:00
pub fn on_pre_event_inner<F, E>(self, trigger: E, cb: F) -> Self
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
2018-11-09 18:40:06 +00:00
self.with(|s| s.set_on_pre_event_inner(trigger, 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.
2018-11-09 18:40:06 +00:00
pub fn on_event_inner<F, E>(self, trigger: E, cb: F) -> Self
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
2018-11-09 18:40:06 +00:00
self.with(|s| s.set_on_event_inner(trigger, cb))
}
/// Registers a callback when the given event is ignored by the child.
2018-11-09 18:40:06 +00:00
pub fn set_on_event<F, E>(&mut self, trigger: E, cb: F)
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: Fn(&mut Cursive) + 'static,
{
let cb = Callback::from_fn(cb);
2018-11-09 18:40:06 +00:00
let action = move |_: &mut T, _: &Event| {
Some(EventResult::Consumed(Some(cb.clone())))
};
2018-11-09 18:40:06 +00:00
self.set_on_event_inner(trigger, action);
}
/// Registers a callback when the given event is received.
///
/// The child will never receive this event.
2018-11-09 18:40:06 +00:00
pub fn set_on_pre_event<F, E>(&mut self, trigger: E, cb: F)
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: 'static + Fn(&mut Cursive),
{
let cb = Callback::from_fn(cb);
// We want to clone the Callback every time we call the closure
2018-11-09 18:40:06 +00:00
let action = move |_: &mut T, _: &Event| {
Some(EventResult::Consumed(Some(cb.clone())))
};
2018-11-09 18:40:06 +00:00
self.set_on_pre_event_inner(trigger, action);
}
/// Registers a callback when the given event is received.
///
/// The given callback will be run before the child view sees the event.
2017-12-08 00:47:56 +00:00
///
2017-10-15 04:18:50 +00:00
/// * 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.
2018-11-09 18:40:06 +00:00
pub fn set_on_pre_event_inner<F, E>(&mut self, trigger: E, cb: F)
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
2018-11-09 18:40:06 +00:00
self.callbacks.push((
trigger.into(),
Action {
phase: TriggerPhase::BeforeChild,
callback: Rc::new(Box::new(cb)),
},
2018-11-09 18:40:06 +00:00
));
}
2017-06-12 23:39:12 +00:00
/// 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.
2018-11-09 18:40:06 +00:00
pub fn set_on_event_inner<F, E>(&mut self, trigger: E, cb: F)
where
2018-11-09 18:40:06 +00:00
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
2017-06-12 23:39:12 +00:00
{
2018-11-09 18:40:06 +00:00
self.callbacks.push((
trigger.into(),
Action {
phase: TriggerPhase::AfterChild,
callback: Rc::new(Box::new(cb)),
},
2018-11-09 18:40:06 +00:00
));
}
inner_getters!(self.view: T);
}
2017-06-12 23:39:12 +00:00
impl<T: View> ViewWrapper for OnEventView<T> {
wrap_impl!(self.view: T);
fn wrap_on_event(&mut self, event: Event) -> EventResult {
2018-11-09 18:40:06 +00:00
// Until we have better closure capture, define captured members separately.
let callbacks = &self.callbacks;
let view = &mut self.view;
// * First, check all pre-child callbacks. Combine them.
// If any gets triggered and returns Some(...), stop right there.
// * Otherwise, give the event to the child view.
// If it returns EventResult::Consumed, stop right there.
// * Finally, check all post-child callbacks. Combine them.
// And just return the result.
// First step: check pre-child
callbacks
.iter()
.filter(|&(_, action)| action.phase == TriggerPhase::BeforeChild)
.filter(|&(trigger, _)| trigger.apply(&event))
.filter_map(|(_, action)| (*action.callback)(view, &event))
.fold(None, |s, r| match s {
// Return `Some()` if any pre-callback was present.
None => Some(r),
Some(c) => Some(c.and(r)),
})
.unwrap_or_else(|| {
// If it was None, it means no pre-callback was triggered.
// So let's give the view a chance!
view.on_event(event.clone())
})
.or_else(|| {
// No pre-child, and the child itself ignored the event?
// Let's have a closer look then, shall we?
callbacks
.iter()
.filter(|&(_, action)| {
action.phase == TriggerPhase::AfterChild
})
.filter(|&(trigger, _)| trigger.apply(&event))
.filter_map(|(_, action)| (*action.callback)(view, &event))
.fold(EventResult::Ignored, EventResult::and)
})
}
}