use crate::event::{Callback, Event, EventResult, EventTrigger};
use crate::view::{View, ViewWrapper};
use crate::Cursive;
use crate::With;
use std::rc::Rc;
pub struct OnEventView<T> {
view: T,
callbacks: Vec<(EventTrigger, Action<T>)>,
}
new_default!(OnEventView<T: Default>);
type InnerCallback<T> = Rc<Box<dyn 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(),
callback: Rc::clone(&self.callback),
}
}
}
#[derive(PartialEq, Clone)]
enum TriggerPhase {
BeforeChild,
AfterChild,
}
impl<T> OnEventView<T> {
pub fn new(view: T) -> Self {
OnEventView {
view,
callbacks: Vec::new(),
}
}
pub fn clear_event<E>(&mut self, event: E)
where
E: Into<Event>,
{
let event = event.into();
self.callbacks
.retain(move |(trigger, _)| !trigger.has_tag(&event));
}
#[must_use]
pub fn on_event<F, E>(self, trigger: E, cb: F) -> Self
where
E: Into<EventTrigger>,
F: 'static + Fn(&mut Cursive),
{
self.with(|s| s.set_on_event(trigger, cb))
}
#[must_use]
pub fn on_pre_event<F, E>(self, trigger: E, cb: F) -> Self
where
E: Into<EventTrigger>,
F: 'static + Fn(&mut Cursive),
{
self.with(|s| s.set_on_pre_event(trigger, cb))
}
#[must_use]
pub fn on_pre_event_inner<F, E>(self, trigger: E, cb: F) -> Self
where
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
self.with(|s| s.set_on_pre_event_inner(trigger, cb))
}
#[must_use]
pub fn on_event_inner<F, E>(self, trigger: E, cb: F) -> Self
where
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
self.with(|s| s.set_on_event_inner(trigger, cb))
}
pub fn set_on_event<F, E>(&mut self, trigger: E, cb: F)
where
E: Into<EventTrigger>,
F: Fn(&mut Cursive) + 'static,
{
let cb = Callback::from_fn(cb);
let action = move |_: &mut T, _: &Event| {
Some(EventResult::Consumed(Some(cb.clone())))
};
self.set_on_event_inner(trigger, action);
}
pub fn set_on_pre_event<F, E>(&mut self, trigger: E, cb: F)
where
E: Into<EventTrigger>,
F: 'static + Fn(&mut Cursive),
{
let cb = Callback::from_fn(cb);
let action = move |_: &mut T, _: &Event| {
Some(EventResult::Consumed(Some(cb.clone())))
};
self.set_on_pre_event_inner(trigger, action);
}
pub fn set_on_pre_event_inner<F, E>(&mut self, trigger: E, cb: F)
where
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
self.callbacks.push((
trigger.into(),
Action {
phase: TriggerPhase::BeforeChild,
callback: Rc::new(Box::new(cb)),
},
));
}
pub fn set_on_event_inner<F, E>(&mut self, trigger: E, cb: F)
where
E: Into<EventTrigger>,
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
{
self.callbacks.push((
trigger.into(),
Action {
phase: TriggerPhase::AfterChild,
callback: Rc::new(Box::new(cb)),
},
));
}
pub fn clear_callbacks(&mut self) {
self.callbacks.clear();
}
inner_getters!(self.view: T);
}
impl<T: View> ViewWrapper for OnEventView<T> {
wrap_impl!(self.view: T);
fn wrap_on_event(&mut self, event: Event) -> EventResult {
let callbacks = &self.callbacks;
let view = &mut self.view;
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 {
None => Some(r),
Some(c) => Some(c.and(r)),
})
.unwrap_or_else(|| {
view.on_event(event.clone())
})
.or_else(|| {
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)
})
}
}