mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Add EventTrigger, refactor OnEventView
This commit is contained in:
parent
3f4719c148
commit
d9d34b4350
@ -26,6 +26,7 @@ enum ColorRole {
|
|||||||
Background,
|
Background,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Backend using BearLibTerminal
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
buttons_pressed: HashSet<MouseButton>,
|
buttons_pressed: HashSet<MouseButton>,
|
||||||
mouse_position: Vec2,
|
mouse_position: Vec2,
|
||||||
@ -35,6 +36,7 @@ pub struct Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
/// Creates a new BearLibTerminal-based backend.
|
||||||
pub fn init() -> Box<backend::Backend> {
|
pub fn init() -> Box<backend::Backend> {
|
||||||
terminal::open("Cursive", 80, 24);
|
terminal::open("Cursive", 80, 24);
|
||||||
terminal::set(terminal::config::Window::empty().resizeable(true));
|
terminal::set(terminal::config::Window::empty().resizeable(true));
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! Ncurses-specific backend.
|
||||||
extern crate ncurses;
|
extern crate ncurses;
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@ -23,6 +24,7 @@ use vec::Vec2;
|
|||||||
use self::super::split_i32;
|
use self::super::split_i32;
|
||||||
use self::ncurses::mmask_t;
|
use self::ncurses::mmask_t;
|
||||||
|
|
||||||
|
/// Backend using ncurses.
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
current_style: Cell<ColorPair>,
|
current_style: Cell<ColorPair>,
|
||||||
|
|
||||||
@ -200,6 +202,7 @@ fn write_to_tty(bytes: &[u8]) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
/// Creates a new ncurses-based backend.
|
||||||
pub fn init() -> Box<backend::Backend> {
|
pub fn init() -> Box<backend::Backend> {
|
||||||
let signals = Some(Signals::new(&[libc::SIGWINCH]).unwrap());
|
let signals = Some(Signals::new(&[libc::SIGWINCH]).unwrap());
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! Pancuses-specific backend.
|
||||||
extern crate pancurses;
|
extern crate pancurses;
|
||||||
|
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@ -22,6 +23,7 @@ use vec::Vec2;
|
|||||||
use self::pancurses::mmask_t;
|
use self::pancurses::mmask_t;
|
||||||
use super::split_i32;
|
use super::split_i32;
|
||||||
|
|
||||||
|
/// Backend using pancurses.
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
// Used
|
// Used
|
||||||
current_style: Cell<ColorPair>,
|
current_style: Cell<ColorPair>,
|
||||||
@ -84,7 +86,8 @@ impl InputParser {
|
|||||||
pancurses::Input::Character(c) => Event::Char(c),
|
pancurses::Input::Character(c) => Event::Char(c),
|
||||||
// TODO: Some key combos are not recognized by pancurses,
|
// TODO: Some key combos are not recognized by pancurses,
|
||||||
// but are sent as Unknown. We could still parse them here.
|
// but are sent as Unknown. We could still parse them here.
|
||||||
pancurses::Input::Unknown(code) => self.key_codes
|
pancurses::Input::Unknown(code) => self
|
||||||
|
.key_codes
|
||||||
// pancurses does some weird keycode mapping
|
// pancurses does some weird keycode mapping
|
||||||
.get(&(code + 256 + 48))
|
.get(&(code + 256 + 48))
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -286,6 +289,7 @@ fn find_closest_pair(pair: ColorPair) -> (i16, i16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
/// Creates a new pancurses-based backend.
|
||||||
pub fn init() -> Box<backend::Backend> {
|
pub fn init() -> Box<backend::Backend> {
|
||||||
// We need to create this now, before ncurses initialization
|
// We need to create this now, before ncurses initialization
|
||||||
// Otherwise ncurses starts its own signal handling and it's a mess.
|
// Otherwise ncurses starts its own signal handling and it's a mess.
|
||||||
@ -523,18 +527,22 @@ where
|
|||||||
| pancurses::BUTTON2_DOUBLE_CLICKED
|
| pancurses::BUTTON2_DOUBLE_CLICKED
|
||||||
| pancurses::BUTTON3_DOUBLE_CLICKED
|
| pancurses::BUTTON3_DOUBLE_CLICKED
|
||||||
| pancurses::BUTTON4_DOUBLE_CLICKED
|
| pancurses::BUTTON4_DOUBLE_CLICKED
|
||||||
| pancurses::BUTTON5_DOUBLE_CLICKED => for _ in 0..2 {
|
| pancurses::BUTTON5_DOUBLE_CLICKED => {
|
||||||
|
for _ in 0..2 {
|
||||||
f(MouseEvent::Press(button));
|
f(MouseEvent::Press(button));
|
||||||
f(MouseEvent::Release(button));
|
f(MouseEvent::Release(button));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
pancurses::BUTTON1_TRIPLE_CLICKED
|
pancurses::BUTTON1_TRIPLE_CLICKED
|
||||||
| pancurses::BUTTON2_TRIPLE_CLICKED
|
| pancurses::BUTTON2_TRIPLE_CLICKED
|
||||||
| pancurses::BUTTON3_TRIPLE_CLICKED
|
| pancurses::BUTTON3_TRIPLE_CLICKED
|
||||||
| pancurses::BUTTON4_TRIPLE_CLICKED
|
| pancurses::BUTTON4_TRIPLE_CLICKED
|
||||||
| pancurses::BUTTON5_TRIPLE_CLICKED => for _ in 0..3 {
|
| pancurses::BUTTON5_TRIPLE_CLICKED => {
|
||||||
|
for _ in 0..3 {
|
||||||
f(MouseEvent::Press(button));
|
f(MouseEvent::Press(button));
|
||||||
f(MouseEvent::Release(button));
|
f(MouseEvent::Release(button));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
_ => debug!("Unknown event: {:032b}", bare_event),
|
_ => debug!("Unknown event: {:032b}", bare_event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,16 @@ use event::Event;
|
|||||||
use theme;
|
use theme;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
|
||||||
|
/// Dummy backend that does nothing and immediately exits.
|
||||||
|
///
|
||||||
|
/// Mostly used for testing.
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
inner_sender: Sender<Option<Event>>,
|
inner_sender: Sender<Option<Event>>,
|
||||||
inner_receiver: Receiver<Option<Event>>,
|
inner_receiver: Receiver<Option<Event>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
/// Creates a new dummy backend.
|
||||||
pub fn init() -> Box<backend::Backend>
|
pub fn init() -> Box<backend::Backend>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
@ -31,6 +31,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
|
/// Backend using termion
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>,
|
terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>,
|
||||||
current_style: Cell<theme::ColorPair>,
|
current_style: Cell<theme::ColorPair>,
|
||||||
@ -210,6 +211,7 @@ impl Effectable for theme::Effect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
/// Creates a new termion-based backend.
|
||||||
pub fn init() -> Box<backend::Backend> {
|
pub fn init() -> Box<backend::Backend> {
|
||||||
print!("{}", termion::cursor::Hide);
|
print!("{}", termion::cursor::Hide);
|
||||||
|
|
||||||
|
85
src/event.rs
85
src/event.rs
@ -29,6 +29,91 @@ pub struct Callback(Rc<Box<Fn(&mut Cursive)>>);
|
|||||||
/// A boxed callback that can be run on `&mut Any`.
|
/// A boxed callback that can be run on `&mut Any`.
|
||||||
pub type AnyCb<'a> = Box<FnMut(&mut Any) + 'a>;
|
pub type AnyCb<'a> = Box<FnMut(&mut Any) + 'a>;
|
||||||
|
|
||||||
|
/// A trigger that only selects some types of events.
|
||||||
|
pub struct EventTrigger(Box<Fn(&Event) -> bool>);
|
||||||
|
|
||||||
|
impl EventTrigger {
|
||||||
|
/// Create a new `EventTrigger` using the given function as filter.
|
||||||
|
pub fn from_fn<F>(f: F) -> Self
|
||||||
|
where
|
||||||
|
F: 'static + Fn(&Event) -> bool,
|
||||||
|
{
|
||||||
|
EventTrigger(Box::new(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if this trigger applies to the given `Event`.
|
||||||
|
pub fn apply(&self, event: &Event) -> bool {
|
||||||
|
(self.0)(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `EventTrigger` that only accepts arrow keys.
|
||||||
|
///
|
||||||
|
/// Only bare arrow keys without modifiers (Shift, Ctrl, Alt) will be accepted.
|
||||||
|
pub fn arrows() -> Self {
|
||||||
|
Self::from_fn(|e| match e {
|
||||||
|
Event::Key(Key::Left)
|
||||||
|
| Event::Key(Key::Down)
|
||||||
|
| Event::Key(Key::Up)
|
||||||
|
| Event::Key(Key::Right) => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `EventTrigger` that only accepts mouse events.
|
||||||
|
pub fn mouse() -> Self {
|
||||||
|
Self::from_fn(|e| match e {
|
||||||
|
Event::Mouse { .. } => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `EventTrigger` that accepts any event.
|
||||||
|
pub fn any() -> Self {
|
||||||
|
Self::from_fn(|_| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `EventTrigger` that doesn't accept any event.
|
||||||
|
pub fn none() -> Self {
|
||||||
|
Self::from_fn(|_| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `EventTrigger` that applies if either `self` or `other` applies.
|
||||||
|
pub fn or<O>(self, other: O) -> Self
|
||||||
|
where
|
||||||
|
O: Into<EventTrigger>,
|
||||||
|
{
|
||||||
|
let other = other.into();
|
||||||
|
Self::from_fn(move |e| self.apply(e) || other.apply(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Event> for EventTrigger {
|
||||||
|
fn from(event: Event) -> Self {
|
||||||
|
Self::from_fn(move |e| *e == event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<char> for EventTrigger {
|
||||||
|
fn from(c: char) -> Self {
|
||||||
|
Self::from(Event::from(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Key> for EventTrigger {
|
||||||
|
fn from(k: Key) -> Self {
|
||||||
|
Self::from(Event::from(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> From<F> for EventTrigger
|
||||||
|
where
|
||||||
|
F: 'static + Fn(&Event) -> bool,
|
||||||
|
{
|
||||||
|
fn from(f: F) -> Self {
|
||||||
|
Self::from_fn(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Callback {
|
impl Callback {
|
||||||
/// Wraps the given function into a `Callback` object.
|
/// Wraps the given function into a `Callback` object.
|
||||||
pub fn from_fn<F>(f: F) -> Self
|
pub fn from_fn<F>(f: F) -> Self
|
||||||
|
@ -123,7 +123,6 @@ mod xy;
|
|||||||
mod div;
|
mod div;
|
||||||
mod utf8;
|
mod utf8;
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
|
|
||||||
pub use cursive::{CbFunc, Cursive, ScreenId};
|
pub use cursive::{CbFunc, Cursive, ScreenId};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use event::{Callback, Event, EventResult};
|
use event::{Callback, Event, EventResult, EventTrigger};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use view::{View, ViewWrapper};
|
use view::{View, ViewWrapper};
|
||||||
use Cursive;
|
use Cursive;
|
||||||
@ -10,10 +9,8 @@ use With;
|
|||||||
/// This view registers a set of callbacks tied to specific events, to be run
|
/// This view registers a set of callbacks tied to specific events, to be run
|
||||||
/// in certain conditions.
|
/// in certain conditions.
|
||||||
///
|
///
|
||||||
/// **Note**: only one callback can be registered per event. Trying to register
|
/// * Some callbacks are called only for events ignored by the wrapped view.
|
||||||
/// a new one will replace any existing one for that event.
|
|
||||||
///
|
///
|
||||||
/// * Some callbacks are called only for vents ignored by the wrapped view
|
|
||||||
/// (those registered by [`on_event`] or [`on_event_inner`])
|
/// (those registered by [`on_event`] or [`on_event_inner`])
|
||||||
/// * Others are processed first, and can control whether the child view should
|
/// * Others are processed first, and can control whether the child view should
|
||||||
/// be given the event (those registered by [`on_pre_event`] or
|
/// be given the event (those registered by [`on_pre_event`] or
|
||||||
@ -43,10 +40,10 @@ use With;
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct OnEventView<T: View> {
|
pub struct OnEventView<T: View> {
|
||||||
view: T,
|
view: T,
|
||||||
callbacks: HashMap<Event, Action<T>>,
|
callbacks: Vec<(EventTrigger, Action<T>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type InnerCallback<T> = Rc<Box<Fn(&mut T) -> Option<EventResult>>>;
|
type InnerCallback<T> = Rc<Box<Fn(&mut T, &Event) -> Option<EventResult>>>;
|
||||||
|
|
||||||
struct Action<T> {
|
struct Action<T> {
|
||||||
phase: TriggerPhase,
|
phase: TriggerPhase,
|
||||||
@ -73,19 +70,19 @@ impl<T: View> OnEventView<T> {
|
|||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
OnEventView {
|
OnEventView {
|
||||||
view,
|
view,
|
||||||
callbacks: HashMap::new(),
|
callbacks: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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>(self, event: E, cb: F) -> Self
|
pub fn on_event<F, E>(self, trigger: E, cb: F) -> Self
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: 'static + Fn(&mut Cursive),
|
F: 'static + Fn(&mut Cursive),
|
||||||
{
|
{
|
||||||
self.with(|s| s.set_on_event(event, cb))
|
self.with(|s| s.set_on_event(trigger, cb))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is received.
|
/// Registers a callback when the given event is received.
|
||||||
@ -93,12 +90,12 @@ impl<T: View> OnEventView<T> {
|
|||||||
/// The child will never receive this event.
|
/// The child will never receive this event.
|
||||||
///
|
///
|
||||||
/// Chainable variant.
|
/// Chainable variant.
|
||||||
pub fn on_pre_event<F, E>(self, event: E, cb: F) -> Self
|
pub fn on_pre_event<F, E>(self, trigger: E, cb: F) -> Self
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: 'static + Fn(&mut Cursive),
|
F: 'static + Fn(&mut Cursive),
|
||||||
{
|
{
|
||||||
self.with(|s| s.set_on_pre_event(event, cb))
|
self.with(|s| s.set_on_pre_event(trigger, cb))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is received.
|
/// Registers a callback when the given event is received.
|
||||||
@ -111,12 +108,12 @@ impl<T: View> OnEventView<T> {
|
|||||||
/// result.
|
/// result.
|
||||||
///
|
///
|
||||||
/// Chainable variant.
|
/// Chainable variant.
|
||||||
pub fn on_pre_event_inner<F, E>(self, event: E, cb: F) -> Self
|
pub fn on_pre_event_inner<F, E>(self, trigger: E, cb: F) -> Self
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
||||||
{
|
{
|
||||||
self.with(|s| s.set_on_pre_event_inner(event, cb))
|
self.with(|s| s.set_on_pre_event_inner(trigger, cb))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is ignored by the child.
|
/// Registers a callback when the given event is ignored by the child.
|
||||||
@ -126,41 +123,43 @@ impl<T: View> OnEventView<T> {
|
|||||||
/// If the result is not `None`, it will be processed as well.
|
/// If the result is not `None`, it will be processed as well.
|
||||||
///
|
///
|
||||||
/// Chainable variant.
|
/// Chainable variant.
|
||||||
pub fn on_event_inner<F, E>(self, event: E, cb: F) -> Self
|
pub fn on_event_inner<F, E>(self, trigger: E, cb: F) -> Self
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
||||||
{
|
{
|
||||||
self.with(|s| s.set_on_event_inner(event, cb))
|
self.with(|s| s.set_on_event_inner(trigger, cb))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is ignored by the child.
|
/// 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)
|
pub fn set_on_event<F, E>(&mut self, trigger: E, cb: F)
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: Fn(&mut Cursive) + 'static,
|
F: Fn(&mut Cursive) + 'static,
|
||||||
{
|
{
|
||||||
let cb = Callback::from_fn(cb);
|
let cb = Callback::from_fn(cb);
|
||||||
let action =
|
let action = move |_: &mut T, _: &Event| {
|
||||||
move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));
|
Some(EventResult::Consumed(Some(cb.clone())))
|
||||||
|
};
|
||||||
|
|
||||||
self.set_on_event_inner(event, action);
|
self.set_on_event_inner(trigger, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is received.
|
/// Registers a callback when the given event is received.
|
||||||
///
|
///
|
||||||
/// The child will never receive this event.
|
/// The child will never receive this event.
|
||||||
pub fn set_on_pre_event<F, E>(&mut self, event: E, cb: F)
|
pub fn set_on_pre_event<F, E>(&mut self, trigger: E, cb: F)
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: 'static + Fn(&mut Cursive),
|
F: 'static + Fn(&mut Cursive),
|
||||||
{
|
{
|
||||||
let cb = Callback::from_fn(cb);
|
let cb = Callback::from_fn(cb);
|
||||||
// We want to clone the Callback every time we call the closure
|
// We want to clone the Callback every time we call the closure
|
||||||
let action =
|
let action = move |_: &mut T, _: &Event| {
|
||||||
move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));
|
Some(EventResult::Consumed(Some(cb.clone())))
|
||||||
|
};
|
||||||
|
|
||||||
self.set_on_pre_event_inner(event, action);
|
self.set_on_pre_event_inner(trigger, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is received.
|
/// Registers a callback when the given event is received.
|
||||||
@ -171,18 +170,18 @@ impl<T: View> OnEventView<T> {
|
|||||||
/// usual.
|
/// usual.
|
||||||
/// * Otherwise, it bypasses the child view and directly processes the
|
/// * Otherwise, it bypasses the child view and directly processes the
|
||||||
/// result.
|
/// result.
|
||||||
pub fn set_on_pre_event_inner<F, E>(&mut self, event: E, cb: F)
|
pub fn set_on_pre_event_inner<F, E>(&mut self, trigger: E, cb: F)
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
||||||
{
|
{
|
||||||
self.callbacks.insert(
|
self.callbacks.push((
|
||||||
event.into(),
|
trigger.into(),
|
||||||
Action {
|
Action {
|
||||||
phase: TriggerPhase::BeforeChild,
|
phase: TriggerPhase::BeforeChild,
|
||||||
callback: Rc::new(Box::new(cb)),
|
callback: Rc::new(Box::new(cb)),
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given event is ignored by the child.
|
/// Registers a callback when the given event is ignored by the child.
|
||||||
@ -190,18 +189,18 @@ impl<T: View> OnEventView<T> {
|
|||||||
/// If the child view ignores the event, `cb` will be called with the
|
/// If the child view ignores the event, `cb` will be called with the
|
||||||
/// child view as argument.
|
/// child view as argument.
|
||||||
/// If the result is not `None`, it will be processed as well.
|
/// 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)
|
pub fn set_on_event_inner<F, E>(&mut self, trigger: E, cb: F)
|
||||||
where
|
where
|
||||||
E: Into<Event>,
|
E: Into<EventTrigger>,
|
||||||
F: Fn(&mut T) -> Option<EventResult> + 'static,
|
F: Fn(&mut T, &Event) -> Option<EventResult> + 'static,
|
||||||
{
|
{
|
||||||
self.callbacks.insert(
|
self.callbacks.push((
|
||||||
event.into(),
|
trigger.into(),
|
||||||
Action {
|
Action {
|
||||||
phase: TriggerPhase::AfterChild,
|
phase: TriggerPhase::AfterChild,
|
||||||
callback: Rc::new(Box::new(cb)),
|
callback: Rc::new(Box::new(cb)),
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_getters!(self.view: T);
|
inner_getters!(self.view: T);
|
||||||
@ -211,22 +210,44 @@ impl<T: View> ViewWrapper for OnEventView<T> {
|
|||||||
wrap_impl!(self.view: T);
|
wrap_impl!(self.view: T);
|
||||||
|
|
||||||
fn wrap_on_event(&mut self, event: Event) -> EventResult {
|
fn wrap_on_event(&mut self, event: Event) -> EventResult {
|
||||||
let action = self.callbacks.get(&event).cloned();
|
// Until we have better closure capture, define captured members separately.
|
||||||
let pre_child = action
|
let callbacks = &self.callbacks;
|
||||||
.as_ref()
|
let view = &mut self.view;
|
||||||
.map(|a| a.phase == TriggerPhase::BeforeChild)
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if pre_child {
|
// * First, check all pre-child callbacks. Combine them.
|
||||||
action
|
// If any gets triggered and returns Some(...), stop right there.
|
||||||
.and_then(|a| (*a.callback)(&mut self.view))
|
// * Otherwise, give the event to the child view.
|
||||||
.unwrap_or_else(|| self.view.on_event(event))
|
// If it returns EventResult::Consumed, stop right there.
|
||||||
} else {
|
// * Finally, check all post-child callbacks. Combine them.
|
||||||
self.view.on_event(event).or_else(|| {
|
// And just return the result.
|
||||||
action
|
|
||||||
.and_then(|a| (*a.callback)(&mut self.view))
|
// First step: check pre-child
|
||||||
.unwrap_or(EventResult::Ignored)
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user