This is in contrast to not dispatching the event altogether in `Flex` when the event is not contained in the flex element bounds. That approach was problematic because it didn't give an opportunity to `MouseEventHandler`s to handle mouse move events when they didn't intersect with the element bounds, causing elements to never clear their hover state, cursor style, etc.
149 lines
4.2 KiB
Rust
149 lines
4.2 KiB
Rust
use pathfinder_geometry::rect::RectF;
|
|
use serde_json::json;
|
|
|
|
use crate::{
|
|
geometry::vector::Vector2F, DebugContext, Element, ElementBox, Event, EventContext,
|
|
LayoutContext, NavigationDirection, PaintContext, SizeConstraint,
|
|
};
|
|
|
|
pub struct EventHandler {
|
|
child: ElementBox,
|
|
capture: Option<Box<dyn FnMut(&Event, RectF, &mut EventContext) -> bool>>,
|
|
mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
|
|
right_mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
|
|
navigate_mouse_down: Option<Box<dyn FnMut(NavigationDirection, &mut EventContext) -> bool>>,
|
|
}
|
|
|
|
impl EventHandler {
|
|
pub fn new(child: ElementBox) -> Self {
|
|
Self {
|
|
child,
|
|
capture: None,
|
|
mouse_down: None,
|
|
right_mouse_down: None,
|
|
navigate_mouse_down: None,
|
|
}
|
|
}
|
|
|
|
pub fn on_mouse_down<F>(mut self, callback: F) -> Self
|
|
where
|
|
F: 'static + FnMut(&mut EventContext) -> bool,
|
|
{
|
|
self.mouse_down = Some(Box::new(callback));
|
|
self
|
|
}
|
|
|
|
pub fn on_right_mouse_down<F>(mut self, callback: F) -> Self
|
|
where
|
|
F: 'static + FnMut(&mut EventContext) -> bool,
|
|
{
|
|
self.right_mouse_down = Some(Box::new(callback));
|
|
self
|
|
}
|
|
|
|
pub fn on_navigate_mouse_down<F>(mut self, callback: F) -> Self
|
|
where
|
|
F: 'static + FnMut(NavigationDirection, &mut EventContext) -> bool,
|
|
{
|
|
self.navigate_mouse_down = Some(Box::new(callback));
|
|
self
|
|
}
|
|
|
|
pub fn capture<F>(mut self, callback: F) -> Self
|
|
where
|
|
F: 'static + FnMut(&Event, RectF, &mut EventContext) -> bool,
|
|
{
|
|
self.capture = Some(Box::new(callback));
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Element for EventHandler {
|
|
type LayoutState = ();
|
|
type PaintState = ();
|
|
|
|
fn layout(
|
|
&mut self,
|
|
constraint: SizeConstraint,
|
|
cx: &mut LayoutContext,
|
|
) -> (Vector2F, Self::LayoutState) {
|
|
let size = self.child.layout(constraint, cx);
|
|
(size, ())
|
|
}
|
|
|
|
fn paint(
|
|
&mut self,
|
|
bounds: RectF,
|
|
visible_bounds: RectF,
|
|
_: &mut Self::LayoutState,
|
|
cx: &mut PaintContext,
|
|
) -> Self::PaintState {
|
|
self.child.paint(bounds.origin(), visible_bounds, cx);
|
|
}
|
|
|
|
fn dispatch_event(
|
|
&mut self,
|
|
event: &Event,
|
|
_: RectF,
|
|
visible_bounds: RectF,
|
|
_: &mut Self::LayoutState,
|
|
_: &mut Self::PaintState,
|
|
cx: &mut EventContext,
|
|
) -> bool {
|
|
if let Some(capture) = self.capture.as_mut() {
|
|
if capture(event, visible_bounds, cx) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if self.child.dispatch_event(event, cx) {
|
|
true
|
|
} else {
|
|
match event {
|
|
Event::LeftMouseDown { position, .. } => {
|
|
if let Some(callback) = self.mouse_down.as_mut() {
|
|
if visible_bounds.contains_point(*position) {
|
|
return callback(cx);
|
|
}
|
|
}
|
|
false
|
|
}
|
|
Event::RightMouseDown { position, .. } => {
|
|
if let Some(callback) = self.right_mouse_down.as_mut() {
|
|
if visible_bounds.contains_point(*position) {
|
|
return callback(cx);
|
|
}
|
|
}
|
|
false
|
|
}
|
|
Event::NavigateMouseDown {
|
|
position,
|
|
direction,
|
|
..
|
|
} => {
|
|
if let Some(callback) = self.navigate_mouse_down.as_mut() {
|
|
if visible_bounds.contains_point(*position) {
|
|
return callback(*direction, cx);
|
|
}
|
|
}
|
|
false
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn debug(
|
|
&self,
|
|
_: RectF,
|
|
_: &Self::LayoutState,
|
|
_: &Self::PaintState,
|
|
cx: &DebugContext,
|
|
) -> serde_json::Value {
|
|
json!({
|
|
"type": "EventHandler",
|
|
"child": self.child.debug(cx),
|
|
})
|
|
}
|
|
}
|