2019-02-28 23:54:12 +00:00
|
|
|
use crate::event::{Callback, Event, EventResult, EventTrigger};
|
|
|
|
use crate::view::{View, ViewWrapper};
|
|
|
|
use crate::Cursive;
|
|
|
|
use crate::With;
|
2019-03-01 00:04:14 +00:00
|
|
|
use std::rc::Rc;
|
2015-05-16 00:56:38 +00:00
|
|
|
|
2017-12-08 00:47:56 +00:00
|
|
|
/// A wrapper view that can react to events.
|
2015-05-16 00:56:38 +00:00
|
|
|
///
|
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.
|
2018-01-11 17:49:48 +00:00
|
|
|
///
|
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
|
2017-12-15 07:45:14 +00:00
|
|
|
/// 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
|
|
|
|
///
|
|
|
|
/// ```
|
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> {
|
2018-01-26 21:30:23 +00:00
|
|
|
view: T,
|
2018-11-09 18:40:06 +00:00
|
|
|
callbacks: Vec<(EventTrigger, Action<T>)>,
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 23:55:02 +00:00
|
|
|
type InnerCallback<T> = Rc<Box<dyn Fn(&mut T, &Event) -> Option<EventResult>>>;
|
2017-08-23 23:43:17 +00:00
|
|
|
|
|
|
|
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),
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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 {
|
2018-04-10 18:53:25 +00:00
|
|
|
view,
|
2018-11-09 18:40:06 +00:00
|
|
|
callbacks: Vec::new(),
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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:54:57 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use cursive::views::{OnEventView, DummyView};
|
|
|
|
/// # use cursive::event::{Key, EventTrigger};
|
|
|
|
/// let view = OnEventView::new(DummyView)
|
|
|
|
/// .on_event('q', |s| s.quit())
|
|
|
|
/// .on_event(Key::Esc, |s| {
|
|
|
|
/// s.pop_layer();
|
|
|
|
/// })
|
|
|
|
/// .on_event(EventTrigger::mouse(), |s| {
|
|
|
|
/// s.add_layer(DummyView);
|
|
|
|
/// });
|
|
|
|
/// ```
|
2018-11-09 18:40:06 +00:00
|
|
|
pub fn on_event<F, E>(self, trigger: E, cb: F) -> Self
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
2018-03-16 22:50:56 +00:00
|
|
|
F: 'static + Fn(&mut Cursive),
|
2015-05-16 00:56:38 +00:00
|
|
|
{
|
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
|
|
|
}
|
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.
|
2018-11-09 18:40:06 +00:00
|
|
|
pub fn on_pre_event<F, E>(self, trigger: E, cb: F) -> Self
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
2018-03-16 22:50:56 +00:00
|
|
|
F: 'static + Fn(&mut Cursive),
|
2017-08-23 23:43:17 +00:00
|
|
|
{
|
2018-11-09 18:40:06 +00:00
|
|
|
self.with(|s| s.set_on_pre_event(trigger, cb))
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2017-08-23 23:43:17 +00:00
|
|
|
///
|
|
|
|
/// Chainable variant.
|
2018-11-09 18:40:06 +00:00
|
|
|
pub fn on_pre_event_inner<F, E>(self, trigger: E, cb: F) -> Self
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
|
|
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
2017-08-23 23:43:17 +00:00
|
|
|
{
|
2018-11-09 18:40:06 +00:00
|
|
|
self.with(|s| s.set_on_pre_event_inner(trigger, cb))
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers a callback when the given event is ignored by the child.
|
|
|
|
///
|
2018-11-09 18:54:57 +00:00
|
|
|
/// This is an advanced method to get more control.
|
2018-11-09 22:33:43 +00:00
|
|
|
/// [`on_event`] may be easier to use.
|
2018-11-09 18:54:57 +00:00
|
|
|
///
|
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.
|
|
|
|
///
|
|
|
|
/// Chainable variant.
|
2018-11-09 18:54:57 +00:00
|
|
|
///
|
2018-11-09 22:33:43 +00:00
|
|
|
/// [`on_event`]: OnEventView::on_event()
|
|
|
|
///
|
2018-11-09 18:54:57 +00:00
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use cursive::views::{DummyView, OnEventView};
|
|
|
|
/// # use cursive::event::{Event, EventTrigger, MouseEvent, EventResult};
|
|
|
|
/// let view = OnEventView::new(DummyView)
|
|
|
|
/// .on_event_inner(
|
|
|
|
/// EventTrigger::mouse(),
|
|
|
|
/// |d: &mut DummyView, e: &Event| {
|
|
|
|
/// if let &Event::Mouse { event: MouseEvent::Press(_), .. } = e {
|
|
|
|
/// // Do something on mouse press
|
|
|
|
/// Some(EventResult::with_cb(|s| {
|
|
|
|
/// s.pop_layer();
|
|
|
|
/// }))
|
|
|
|
/// } else {
|
|
|
|
/// // Otherwise, don't do anything
|
|
|
|
/// None
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// );
|
|
|
|
/// ```
|
2018-11-09 18:40:06 +00:00
|
|
|
pub fn on_event_inner<F, E>(self, trigger: E, cb: F) -> Self
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
|
|
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
2017-08-23 23:43:17 +00:00
|
|
|
{
|
2018-11-09 18:40:06 +00:00
|
|
|
self.with(|s| s.set_on_event_inner(trigger, cb))
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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)
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
2018-03-16 22:50:56 +00:00
|
|
|
F: Fn(&mut Cursive) + 'static,
|
2017-08-23 23:43:17 +00:00
|
|
|
{
|
|
|
|
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())))
|
|
|
|
};
|
2017-08-23 23:43:17 +00:00
|
|
|
|
2018-11-09 18:40:06 +00:00
|
|
|
self.set_on_event_inner(trigger, action);
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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)
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
2018-03-16 22:50:56 +00:00
|
|
|
F: 'static + Fn(&mut Cursive),
|
2017-08-23 23:43:17 +00:00
|
|
|
{
|
|
|
|
let cb = Callback::from_fn(cb);
|
2017-12-15 07:45:14 +00:00
|
|
|
// 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())))
|
|
|
|
};
|
2017-08-23 23:43:17 +00:00
|
|
|
|
2018-11-09 18:40:06 +00:00
|
|
|
self.set_on_pre_event_inner(trigger, action);
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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)
|
2017-08-23 23:43:17 +00:00
|
|
|
where
|
2018-11-09 18:40:06 +00:00
|
|
|
E: Into<EventTrigger>,
|
|
|
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
2017-08-23 23:43:17 +00:00
|
|
|
{
|
2018-11-09 18:40:06 +00:00
|
|
|
self.callbacks.push((
|
|
|
|
trigger.into(),
|
2017-08-23 23:43:17 +00:00
|
|
|
Action {
|
|
|
|
phase: TriggerPhase::BeforeChild,
|
|
|
|
callback: Rc::new(Box::new(cb)),
|
|
|
|
},
|
2018-11-09 18:40:06 +00:00
|
|
|
));
|
2017-08-23 23:43:17 +00:00
|
|
|
}
|
|
|
|
|
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.
|
2018-11-09 18:40:06 +00:00
|
|
|
pub fn set_on_event_inner<F, E>(&mut self, trigger: E, cb: F)
|
2017-08-23 23:43:17 +00:00
|
|
|
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(),
|
2017-08-23 23:43:17 +00:00
|
|
|
Action {
|
|
|
|
phase: TriggerPhase::AfterChild,
|
|
|
|
callback: Rc::new(Box::new(cb)),
|
|
|
|
},
|
2018-11-09 18:40:06 +00:00
|
|
|
));
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
2018-01-26 11:06:14 +00:00
|
|
|
|
2018-11-09 18:54:57 +00:00
|
|
|
/// Remove any callbacks defined for this view.
|
|
|
|
pub fn clear_callbacks(&mut self) {
|
|
|
|
self.callbacks.clear();
|
|
|
|
}
|
|
|
|
|
2018-01-27 09:37:08 +00:00
|
|
|
inner_getters!(self.view: T);
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-12 23:39:12 +00:00
|
|
|
impl<T: View> ViewWrapper for OnEventView<T> {
|
2018-01-26 21:30:23 +00:00
|
|
|
wrap_impl!(self.view: 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 {
|
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)
|
2017-08-23 23:43:17 +00:00
|
|
|
})
|
2015-05-16 00:56:38 +00:00
|
|
|
}
|
|
|
|
}
|