mod layout;
mod node;
mod reconcile;
pub(crate) use self::layout::measure_mouse_region;
pub use self::node::MouseRegionNode;
pub(crate) use self::reconcile::reconcile_mouse_region;
use crate::callback::Callback;
use crate::core::element::{Element, ElementKind};
use crate::core::event::{KeyMods, MouseDragEvent, MouseEvent, MouseMoveEvent};
use crate::core::mask::CellMask;
use crate::style::{LayoutConstraints, Length, Style, StyleSlot, VisualEffect};
use std::sync::Arc;
#[derive(Clone, Default)]
pub struct MouseRegion {
pub(crate) child: Option<Box<Element>>,
pub(crate) on_click: Option<Callback<MouseEvent>>,
pub(crate) on_mouse_down: Option<Callback<MouseEvent>>,
pub(crate) bubble_mouse_down: bool,
pub(crate) on_mouse_up: Option<Callback<MouseEvent>>,
pub(crate) on_mouse_move: Option<Callback<MouseMoveEvent>>,
pub(crate) on_drag_start: Option<Callback<MouseDragEvent>>,
pub(crate) on_drag: Option<Callback<MouseDragEvent>>,
pub(crate) on_drag_end: Option<Callback<MouseDragEvent>>,
pub(crate) drag_required_mods: Option<KeyMods>,
pub(crate) on_right_drag_start: Option<Callback<MouseDragEvent>>,
pub(crate) on_right_drag: Option<Callback<MouseDragEvent>>,
pub(crate) on_right_drag_end: Option<Callback<MouseDragEvent>>,
pub(crate) right_drag_required_mods: Option<KeyMods>,
pub(crate) on_hover_change: Option<Callback<bool>>,
pub(crate) hit_test: Option<Arc<dyn Fn(u16, u16) -> bool + Send + Sync>>,
pub(crate) capture_click: bool,
pub(crate) capture_required_mods: Option<KeyMods>,
pub(crate) hover_style: StyleSlot,
pub(crate) hover_effects: Vec<VisualEffect>,
pub(crate) enabled: bool,
}
impl MouseRegion {
pub fn new() -> Self {
Self {
enabled: true,
..Self::default()
}
}
pub fn child(mut self, child: impl Into<Element>) -> Self {
self.child = Some(Box::new(child.into()));
self
}
pub fn on_mouse_move(mut self, cb: Callback<MouseMoveEvent>) -> Self {
self.on_mouse_move = Some(cb);
self
}
pub fn on_drag_start(mut self, cb: Callback<MouseDragEvent>) -> Self {
self.on_drag_start = Some(cb);
self
}
pub fn on_drag(mut self, cb: Callback<MouseDragEvent>) -> Self {
self.on_drag = Some(cb);
self
}
pub fn on_drag_end(mut self, cb: Callback<MouseDragEvent>) -> Self {
self.on_drag_end = Some(cb);
self
}
pub fn drag_requires_mods(mut self, mods: KeyMods) -> Self {
self.drag_required_mods = Some(mods);
self
}
pub fn on_right_drag_start(mut self, cb: Callback<MouseDragEvent>) -> Self {
self.on_right_drag_start = Some(cb);
self
}
pub fn on_right_drag(mut self, cb: Callback<MouseDragEvent>) -> Self {
self.on_right_drag = Some(cb);
self
}
pub fn on_right_drag_end(mut self, cb: Callback<MouseDragEvent>) -> Self {
self.on_right_drag_end = Some(cb);
self
}
pub fn right_drag_requires_mods(mut self, mods: KeyMods) -> Self {
self.right_drag_required_mods = Some(mods);
self
}
pub fn on_hover_change(mut self, cb: Callback<bool>) -> Self {
self.on_hover_change = Some(cb);
self
}
pub fn on_click(mut self, cb: Callback<MouseEvent>) -> Self {
self.on_click = Some(cb);
self
}
pub fn hit_test(mut self, f: impl Fn(u16, u16) -> bool + Send + Sync + 'static) -> Self {
self.hit_test = Some(Arc::new(f));
self
}
pub fn cell_mask(mut self, mask: Arc<CellMask>) -> Self {
let m = Arc::clone(&mask);
self.hit_test = Some(Arc::new(move |x, y| m.test_scope_local(x as i16, y as i16)));
self
}
pub fn on_mouse_down(mut self, cb: Callback<MouseEvent>) -> Self {
self.on_mouse_down = Some(cb);
self
}
pub fn bubble_mouse_down(mut self, bubble: bool) -> Self {
self.bubble_mouse_down = bubble;
self
}
pub fn on_mouse_up(mut self, cb: Callback<MouseEvent>) -> Self {
self.on_mouse_up = Some(cb);
self
}
pub fn capture_click(mut self, capture: bool) -> Self {
self.capture_click = capture;
self
}
pub fn capture_requires_mods(mut self, mods: KeyMods) -> Self {
self.capture_required_mods = Some(mods);
self
}
pub fn hover_style(mut self, style: Style) -> Self {
self.hover_style = StyleSlot::Replace(style);
self
}
pub fn extend_hover_style(mut self, style: Style) -> Self {
self.hover_style = StyleSlot::Extend(style);
self
}
pub fn inherit_hover_style(mut self) -> Self {
self.hover_style = StyleSlot::Inherit;
self
}
pub fn hover_effect(mut self, effect: VisualEffect) -> Self {
self.hover_effects.push(effect);
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
}
impl From<MouseRegion> for Element {
fn from(value: MouseRegion) -> Self {
let (min_w, min_h) = measure_mouse_region(&value, None, None);
Element::new(ElementKind::MouseRegion(value)).with_layout(
LayoutConstraints::default()
.min_width(Length::Px(min_w))
.min_height(Length::Px(min_h)),
)
}
}
impl crate::layout::hash::LayoutHash for MouseRegion {
fn layout_hash(
&self,
hasher: &mut impl std::hash::Hasher,
recurse: &dyn Fn(&Element) -> Option<u64>,
) -> Option<()> {
use std::hash::Hash;
self.enabled.hash(hasher);
self.on_click.is_some().hash(hasher);
self.on_mouse_down.is_some().hash(hasher);
self.bubble_mouse_down.hash(hasher);
self.on_mouse_up.is_some().hash(hasher);
self.on_mouse_move.is_some().hash(hasher);
self.on_drag_start.is_some().hash(hasher);
self.on_drag.is_some().hash(hasher);
self.on_drag_end.is_some().hash(hasher);
self.drag_required_mods.hash(hasher);
self.on_right_drag_start.is_some().hash(hasher);
self.on_right_drag.is_some().hash(hasher);
self.on_right_drag_end.is_some().hash(hasher);
self.right_drag_required_mods.hash(hasher);
self.on_hover_change.is_some().hash(hasher);
self.capture_click.hash(hasher);
self.capture_required_mods.hash(hasher);
self.hover_style.hash(hasher);
self.hover_effects.hash(hasher);
if let Some(child) = self.child.as_ref() {
recurse(child.as_ref())?.hash(hasher);
}
Some(())
}
}