tui_lipan/widgets/mouse_region/
mod.rs1mod layout;
4mod node;
5mod reconcile;
6
7pub(crate) use self::layout::measure_mouse_region;
8pub use self::node::MouseRegionNode;
9pub(crate) use self::reconcile::reconcile_mouse_region;
10
11use crate::callback::Callback;
12use crate::core::element::{Element, ElementKind};
13use crate::core::event::{KeyMods, MouseDragEvent, MouseEvent, MouseMoveEvent};
14use crate::core::mask::CellMask;
15use crate::style::{LayoutConstraints, Length, Style, StyleSlot, VisualEffect};
16use std::sync::Arc;
17
18pub const DEFAULT_DRAG_THRESHOLD: (u16, u16) = (3, 1);
24
25#[derive(Clone, Default)]
27pub struct MouseRegion {
28 pub(crate) child: Option<Box<Element>>,
29 pub(crate) on_click: Option<Callback<MouseEvent>>,
30 pub(crate) on_mouse_down: Option<Callback<MouseEvent>>,
31 pub(crate) bubble_mouse_down: bool,
32 pub(crate) on_mouse_up: Option<Callback<MouseEvent>>,
33 pub(crate) on_mouse_move: Option<Callback<MouseMoveEvent>>,
34 pub(crate) on_drag_start: Option<Callback<MouseDragEvent>>,
35 pub(crate) on_drag: Option<Callback<MouseDragEvent>>,
36 pub(crate) on_drag_end: Option<Callback<MouseDragEvent>>,
37 pub(crate) drag_required_mods: Option<KeyMods>,
38 pub(crate) drag_threshold: Option<(u16, u16)>,
39 pub(crate) on_right_drag_start: Option<Callback<MouseDragEvent>>,
40 pub(crate) on_right_drag: Option<Callback<MouseDragEvent>>,
41 pub(crate) on_right_drag_end: Option<Callback<MouseDragEvent>>,
42 pub(crate) right_drag_required_mods: Option<KeyMods>,
43 pub(crate) on_hover_change: Option<Callback<bool>>,
44 pub(crate) hit_test: Option<Arc<dyn Fn(u16, u16) -> bool + Send + Sync>>,
45 pub(crate) capture_click: bool,
46 pub(crate) capture_required_mods: Option<KeyMods>,
47 pub(crate) hover_style: StyleSlot,
48 pub(crate) hover_effects: Vec<VisualEffect>,
49 pub(crate) enabled: bool,
50}
51
52impl MouseRegion {
53 pub fn new() -> Self {
55 Self {
56 enabled: true,
57 ..Self::default()
58 }
59 }
60
61 pub fn child(mut self, child: impl Into<Element>) -> Self {
63 self.child = Some(Box::new(child.into()));
64 self
65 }
66
67 pub fn on_mouse_move(mut self, cb: Callback<MouseMoveEvent>) -> Self {
69 self.on_mouse_move = Some(cb);
70 self
71 }
72
73 pub fn on_drag_start(mut self, cb: Callback<MouseDragEvent>) -> Self {
75 self.on_drag_start = Some(cb);
76 self
77 }
78
79 pub fn on_drag(mut self, cb: Callback<MouseDragEvent>) -> Self {
81 self.on_drag = Some(cb);
82 self
83 }
84
85 pub fn on_drag_end(mut self, cb: Callback<MouseDragEvent>) -> Self {
87 self.on_drag_end = Some(cb);
88 self
89 }
90
91 pub fn drag_requires_mods(mut self, mods: KeyMods) -> Self {
97 self.drag_required_mods = Some(mods);
98 self
99 }
100
101 pub fn drag_threshold(mut self, columns: u16, rows: u16) -> Self {
111 self.drag_threshold = Some((columns, rows));
112 self
113 }
114
115 pub fn on_right_drag_start(mut self, cb: Callback<MouseDragEvent>) -> Self {
119 self.on_right_drag_start = Some(cb);
120 self
121 }
122
123 pub fn on_right_drag(mut self, cb: Callback<MouseDragEvent>) -> Self {
127 self.on_right_drag = Some(cb);
128 self
129 }
130
131 pub fn on_right_drag_end(mut self, cb: Callback<MouseDragEvent>) -> Self {
135 self.on_right_drag_end = Some(cb);
136 self
137 }
138
139 pub fn right_drag_requires_mods(mut self, mods: KeyMods) -> Self {
144 self.right_drag_required_mods = Some(mods);
145 self
146 }
147
148 pub fn on_hover_change(mut self, cb: Callback<bool>) -> Self {
155 self.on_hover_change = Some(cb);
156 self
157 }
158
159 pub fn on_click(mut self, cb: Callback<MouseEvent>) -> Self {
161 self.on_click = Some(cb);
162 self
163 }
164
165 pub fn hit_test(mut self, f: impl Fn(u16, u16) -> bool + Send + Sync + 'static) -> Self {
167 self.hit_test = Some(Arc::new(f));
168 self
169 }
170
171 pub fn cell_mask(mut self, mask: Arc<CellMask>) -> Self {
173 let m = Arc::clone(&mask);
174 self.hit_test = Some(Arc::new(move |x, y| m.test_scope_local(x as i16, y as i16)));
175 self
176 }
177
178 pub fn on_mouse_down(mut self, cb: Callback<MouseEvent>) -> Self {
180 self.on_mouse_down = Some(cb);
181 self
182 }
183
184 pub fn bubble_mouse_down(mut self, bubble: bool) -> Self {
190 self.bubble_mouse_down = bubble;
191 self
192 }
193
194 pub fn on_mouse_up(mut self, cb: Callback<MouseEvent>) -> Self {
196 self.on_mouse_up = Some(cb);
197 self
198 }
199
200 pub fn capture_click(mut self, capture: bool) -> Self {
202 self.capture_click = capture;
203 self
204 }
205
206 pub fn capture_requires_mods(mut self, mods: KeyMods) -> Self {
213 self.capture_required_mods = Some(mods);
214 self
215 }
216
217 pub fn hover_style(mut self, style: Style) -> Self {
225 self.hover_style = StyleSlot::Replace(style);
226 self
227 }
228
229 pub fn extend_hover_style(mut self, style: Style) -> Self {
231 self.hover_style = StyleSlot::Extend(style);
232 self
233 }
234
235 pub fn inherit_hover_style(mut self) -> Self {
237 self.hover_style = StyleSlot::Inherit;
238 self
239 }
240
241 pub fn hover_effect(mut self, effect: VisualEffect) -> Self {
247 self.hover_effects.push(effect);
248 self
249 }
250
251 pub fn enabled(mut self, enabled: bool) -> Self {
253 self.enabled = enabled;
254 self
255 }
256}
257
258impl From<MouseRegion> for Element {
259 fn from(value: MouseRegion) -> Self {
260 let (min_w, min_h) = measure_mouse_region(&value, None, None);
261 Element::new(ElementKind::MouseRegion(value)).with_layout(
262 LayoutConstraints::default()
263 .min_width(Length::Px(min_w))
264 .min_height(Length::Px(min_h)),
265 )
266 }
267}
268
269impl crate::layout::hash::LayoutHash for MouseRegion {
270 fn layout_hash(
271 &self,
272 hasher: &mut impl std::hash::Hasher,
273 recurse: &dyn Fn(&Element) -> Option<u64>,
274 ) -> Option<()> {
275 use std::hash::Hash;
276 self.enabled.hash(hasher);
277 self.on_click.is_some().hash(hasher);
278 self.on_mouse_down.is_some().hash(hasher);
279 self.bubble_mouse_down.hash(hasher);
280 self.on_mouse_up.is_some().hash(hasher);
281 self.on_mouse_move.is_some().hash(hasher);
282 self.on_drag_start.is_some().hash(hasher);
283 self.on_drag.is_some().hash(hasher);
284 self.on_drag_end.is_some().hash(hasher);
285 self.drag_required_mods.hash(hasher);
286 self.drag_threshold.hash(hasher);
287 self.on_right_drag_start.is_some().hash(hasher);
288 self.on_right_drag.is_some().hash(hasher);
289 self.on_right_drag_end.is_some().hash(hasher);
290 self.right_drag_required_mods.hash(hasher);
291 self.on_hover_change.is_some().hash(hasher);
292 self.capture_click.hash(hasher);
293 self.capture_required_mods.hash(hasher);
294 self.hover_style.hash(hasher);
295 self.hover_effects.hash(hasher);
296 if let Some(child) = self.child.as_ref() {
297 recurse(child.as_ref())?.hash(hasher);
298 }
299 Some(())
300 }
301}