use std::cell::RefCell;
use std::{
collections::VecDeque,
rc::{Rc, Weak},
};
use crate::{control::*, FuiDrawingContext};
use crate::{events::*, Point};
struct QueuedEvent {
pub control: Rc<RefCell<dyn ControlObject>>,
pub event: ControlEvent,
}
pub struct EventProcessor {
hovered_controls: Vec<Weak<RefCell<dyn ControlObject>>>,
hit_tested_control: Option<Weak<RefCell<dyn ControlObject>>>,
captured_control: Option<Weak<RefCell<dyn ControlObject>>>,
focused_control: Option<Weak<RefCell<dyn ControlObject>>>,
cursor_pos: Option<Point>,
gesture_detector: GestureDetector,
event_queue: VecDeque<QueuedEvent>,
}
impl EventProcessor {
pub fn new() -> Self {
EventProcessor {
hovered_controls: Vec::new(),
hit_tested_control: None,
captured_control: None,
focused_control: None,
cursor_pos: None,
gesture_detector: GestureDetector::new(),
event_queue: VecDeque::new(),
}
}
pub fn handle_event(
&mut self,
root_view: &Rc<RefCell<dyn ControlObject>>,
drawing_context: &mut FuiDrawingContext,
event: &InputEvent,
) {
self.handle_keyboard_event(root_view, event);
self.handle_pointer_event(root_view, event);
self.handle_gesture_event(root_view, event);
self.handle_hover_event(root_view, event);
while let Some(queue_event) = self.event_queue.pop_front() {
self.send_event_to_control(
Some(queue_event.control),
drawing_context,
queue_event.event,
);
}
}
fn handle_keyboard_event(
&mut self,
_root_view: &Rc<RefCell<dyn ControlObject>>,
event: &InputEvent,
) {
match event {
InputEvent::KeyboardInput(key_event) => {
self.queue_event(
self.get_focused_control(),
ControlEvent::KeyboardInput(key_event.clone()),
);
}
_ => (),
}
}
fn handle_pointer_event(
&mut self,
root_view: &Rc<RefCell<dyn ControlObject>>,
event: &InputEvent,
) {
match event {
InputEvent::CursorMoved { position, .. } => {
let hit_control = root_view.borrow().hit_test(*position);
self.queue_event(
hit_control,
ControlEvent::PointerMove {
position: *position,
},
);
}
InputEvent::ScrollWheel { delta } => {
let controls: Vec<_> = self.hovered_controls.iter().map(|c| c.upgrade()).collect();
for c in controls {
self.queue_event(c, ControlEvent::ScrollWheel { delta: *delta });
}
}
_ => (),
}
}
fn handle_gesture_event(
&mut self,
root_view: &Rc<RefCell<dyn ControlObject>>,
event: &InputEvent,
) {
self.gesture_detector
.handle_event(root_view, event)
.map(|ev| match ev {
Gesture::TapDown { position } => {
let captured_control = self.get_captured_control();
if let Some(captured_control) = captured_control {
self.queue_event(
Some(captured_control),
ControlEvent::TapDown { position },
);
} else {
let hit_control = root_view.borrow().hit_test(position);
if let Some(ref hit_control) = hit_control {
self.set_focused_control(Some(hit_control.clone()));
self.set_captured_control(Some(hit_control.clone()));
self.queue_event(
self.get_captured_control(),
ControlEvent::TapDown { position },
);
}
}
}
Gesture::TapUp { position } => {
let captured_control = self.get_captured_control();
self.set_captured_control(None);
self.queue_event(captured_control, ControlEvent::TapUp { position });
}
Gesture::TapMove { position } => {
self.queue_event(
self.get_captured_control(),
ControlEvent::TapMove { position },
);
}
});
}
fn handle_hover_event(
&mut self,
root_view: &Rc<RefCell<dyn ControlObject>>,
event: &InputEvent,
) {
match event {
InputEvent::CursorMoved { position, .. } => {
self.cursor_pos = Some(*position);
self.recalculate_hover(root_view);
}
InputEvent::CursorLeft { .. } => {
self.cursor_pos = None;
self.clear_hover();
}
InputEvent::MouseInput {
state: ElementState::Released,
..
} => {
self.recalculate_hover(root_view);
}
_ => (),
}
}
fn recalculate_hover(&mut self, root_view: &Rc<RefCell<dyn ControlObject>>) {
if let Some(position) = self.cursor_pos {
let mut controls_to_hover = root_view.borrow().get_hit_path(position);
let hit_tested_control = controls_to_hover.iter().next().map(|c| c.clone());
if let Some(captured_control) = &self.captured_control {
let mut i = 0;
while i != controls_to_hover.len() {
if !Weak::ptr_eq(&controls_to_hover[i], &captured_control) {
controls_to_hover.remove(i);
} else {
i += 1;
}
}
}
if let Some(currently_hit_tested_control) = self.hit_tested_control.clone() {
let leave = if let Some(hit_tested_control) = &hit_tested_control {
!Weak::ptr_eq(¤tly_hit_tested_control, hit_tested_control)
} else {
true
};
if leave {
self.hit_tested_control = None;
self.queue_event(
currently_hit_tested_control.upgrade(),
ControlEvent::HitTestChange(false),
);
}
}
let to_leave_hover = self
.hovered_controls
.iter()
.rev()
.filter(|&c| !controls_to_hover.iter().any(|c2| Weak::ptr_eq(c, c2)))
.map(|c| c.clone())
.collect::<Vec<_>>();
for c in to_leave_hover {
self.queue_event(c.upgrade(), ControlEvent::HoverChange(false));
}
for control_to_hover in &controls_to_hover {
let exists = self
.hovered_controls
.iter()
.any(|c| Weak::ptr_eq(c, &control_to_hover));
if !exists {
self.queue_event(control_to_hover.upgrade(), ControlEvent::HoverChange(true));
}
}
if self.hit_tested_control.is_none() && hit_tested_control.is_some() {
self.hit_tested_control = hit_tested_control;
self.queue_event(
self.hit_tested_control.as_ref().unwrap().upgrade(),
ControlEvent::HitTestChange(true),
);
}
self.hovered_controls = controls_to_hover;
}
}
fn clear_hover(&mut self) {
if let Some(hit_tested_control) = self.hit_tested_control.take() {
self.queue_event(
hit_tested_control.upgrade(),
ControlEvent::HitTestChange(false),
);
}
let mut to_leave_hover = Vec::new();
to_leave_hover.append(&mut self.hovered_controls);
for c in to_leave_hover {
self.queue_event(c.upgrade(), ControlEvent::HoverChange(false));
}
}
fn send_event_to_control(
&mut self,
control: Option<Rc<RefCell<dyn ControlObject>>>,
drawing_context: &mut FuiDrawingContext,
event: ControlEvent,
) {
if let Some(ref control) = control {
control
.borrow_mut()
.handle_event(drawing_context, self, event);
};
}
}
impl EventContext for EventProcessor {
fn get_captured_control(&self) -> Option<Rc<RefCell<dyn ControlObject>>> {
if let Some(ref control) = self.captured_control {
control.upgrade()
} else {
None
}
}
fn set_captured_control(&mut self, control: Option<Rc<RefCell<dyn ControlObject>>>) {
self.captured_control = control.map(|ref c| Rc::downgrade(c));
}
fn get_focused_control(&self) -> Option<Rc<RefCell<dyn ControlObject>>> {
if let Some(ref control) = self.focused_control {
control.upgrade()
} else {
None
}
}
fn set_focused_control(&mut self, control: Option<Rc<RefCell<dyn ControlObject>>>) {
self.queue_event(self.get_focused_control(), ControlEvent::FocusChange(false));
self.focused_control = control.clone().map(|ref c| Rc::downgrade(c));
self.queue_event(control, ControlEvent::FocusChange(true));
}
fn queue_event(
&mut self,
control: Option<Rc<RefCell<dyn ControlObject>>>,
event: ControlEvent,
) {
if let Some(control) = control {
self.event_queue.push_back(QueuedEvent { control, event })
}
}
}