mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
feat: Add pre-events and inner events to OnEventView
This commit is contained in:
parent
2ac5dcb559
commit
6bb3e88c2e
15
src/event.rs
15
src/event.rs
@ -87,10 +87,21 @@ impl EventResult {
|
|||||||
cb(s);
|
cb(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `self` if it is not `Event::Ignored`, otherwise returns `f()`.
|
||||||
|
pub fn or_else<F>(self, f: F) -> Self
|
||||||
|
where
|
||||||
|
F: FnOnce() -> EventResult,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
EventResult::Ignored => f(),
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A non-character key on the keyboard
|
/// A non-character key on the keyboard
|
||||||
#[derive(PartialEq,Eq,Clone,Copy,Hash,Debug)]
|
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
/// Both Enter (or Return) and numpad Enter
|
/// Both Enter (or Return) and numpad Enter
|
||||||
Enter,
|
Enter,
|
||||||
@ -186,7 +197,7 @@ impl Key {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an event as seen by the application.
|
/// Represents an event as seen by the application.
|
||||||
#[derive(PartialEq,Eq,Clone,Hash,Debug)]
|
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
/// Event fired when the window is resized.
|
/// Event fired when the window is resized.
|
||||||
WindowResize,
|
WindowResize,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
use Cursive;
|
use Cursive;
|
||||||
|
use With;
|
||||||
use event::{Callback, Event, EventResult};
|
use event::{Callback, Event, EventResult};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
use view::{View, ViewWrapper};
|
use view::{View, ViewWrapper};
|
||||||
use With;
|
|
||||||
|
|
||||||
/// A simple wrapper view that catches some ignored event from its child.
|
/// A simple wrapper view that catches some ignored event from its child.
|
||||||
///
|
///
|
||||||
@ -20,15 +20,37 @@ use With;
|
|||||||
/// .on_event(event::Key::Esc, |s| s.quit());
|
/// .on_event(event::Key::Esc, |s| s.quit());
|
||||||
/// ```
|
/// ```
|
||||||
pub struct OnEventView<T: View> {
|
pub struct OnEventView<T: View> {
|
||||||
content: T,
|
inner: T,
|
||||||
callbacks: HashMap<Event, Callback>,
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> OnEventView<T> {
|
impl<T: View> OnEventView<T> {
|
||||||
/// Wraps the given view in a new OnEventView.
|
/// Wraps the given view in a new OnEventView.
|
||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
OnEventView {
|
OnEventView {
|
||||||
content: view,
|
inner: view,
|
||||||
callbacks: HashMap::new(),
|
callbacks: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,32 +58,144 @@ 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: Into<Event>>(self, event: E, cb: F) -> Self
|
pub fn on_event<F, E>(self, event: E, cb: F) -> Self
|
||||||
where F: Fn(&mut Cursive) + 'static
|
where
|
||||||
|
E: Into<Event>,
|
||||||
|
F: Fn(&mut Cursive) + 'static,
|
||||||
{
|
{
|
||||||
self.with(|s| s.set_on_event(event, cb))
|
self.with(|s| s.set_on_event(event, cb))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is ignored by the child.
|
/// Registers a callback when the given event is received.
|
||||||
pub fn set_on_event<F, E: Into<Event>>(&mut self, event: E, cb: F)
|
///
|
||||||
where F: Fn(&mut Cursive) + 'static
|
/// 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.callbacks.insert(event.into(), Callback::from_fn(cb));
|
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)),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
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,
|
||||||
|
{
|
||||||
|
self.callbacks.insert(
|
||||||
|
event.into(),
|
||||||
|
Action {
|
||||||
|
phase: TriggerPhase::AfterChild,
|
||||||
|
callback: Rc::new(Box::new(cb)),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: View> ViewWrapper for OnEventView<T> {
|
impl<T: View> ViewWrapper for OnEventView<T> {
|
||||||
wrap_impl!(self.content: T);
|
wrap_impl!(self.inner: T);
|
||||||
|
|
||||||
fn wrap_on_event(&mut self, event: Event) -> EventResult {
|
fn wrap_on_event(&mut self, event: Event) -> EventResult {
|
||||||
match self.content.on_event(event.clone()) {
|
let action = self.callbacks.get(&event).cloned();
|
||||||
EventResult::Ignored => {
|
let pre_child = action
|
||||||
match self.callbacks.get(&event) {
|
.as_ref()
|
||||||
None => EventResult::Ignored,
|
.map(|a| a.phase == TriggerPhase::BeforeChild)
|
||||||
Some(cb) => EventResult::Consumed(Some(cb.clone())),
|
.unwrap_or(false);
|
||||||
}
|
|
||||||
}
|
if pre_child {
|
||||||
res => res,
|
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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user