1use std::{cell::Cell, collections::HashMap, rc::Rc};
14
15use crossterm::event::Event;
16use ratatui::layout::Rect;
17
18#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
20pub enum EventResult {
21 #[default]
23 Ignored,
24 Consumed,
26}
27
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
30pub enum EventPriority {
31 Low = 0,
32 #[default]
33 Normal = 1,
34 High = 2,
35}
36
37#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
42pub struct LayerId(u64);
43
44#[derive(Clone, Copy, PartialEq, Eq, Debug)]
46pub struct InputLayer {
47 pub(crate) id: LayerId,
48}
49
50#[derive(Clone, Copy, PartialEq, Eq)]
52pub enum EventScope {
53 Current,
56 Layer(InputLayer),
58 Global,
60}
61
62#[derive(Clone, Copy, Default)]
64pub struct EventOptions {
65 pub hit_test: bool,
68}
69
70#[derive(Clone, Copy)]
73pub(crate) struct CurrentLayer(pub(crate) LayerId);
74
75struct LayerEntry {
77 id: LayerId,
78 blocks_lower: bool,
80}
81
82struct HandlerEntry {
84 layer: Option<LayerId>,
86 priority: EventPriority,
87 order: usize,
89 options: EventOptions,
90 area: Rc<Cell<Rect>>,
92 f: Box<dyn FnMut(Event) -> EventResult>,
93}
94
95#[derive(Default)]
97pub(crate) struct InputRuntime {
98 layers: Vec<LayerEntry>,
99 handlers: Vec<HandlerEntry>,
100 next_layer_id: u64,
101 root_layer: Option<LayerId>,
102}
103
104impl InputRuntime {
105 pub(crate) fn begin_frame(&mut self) {
107 self.layers.clear();
108 self.handlers.clear();
109 let root = self.mint_layer_id();
110 self.root_layer = Some(root);
111 self.layers.push(LayerEntry {
112 id: root,
113 blocks_lower: false,
114 });
115 }
116
117 pub(crate) fn root_layer(&self) -> LayerId {
119 self.root_layer.expect("begin_frame 未调用")
120 }
121
122 fn mint_layer_id(&mut self) -> LayerId {
123 let id = LayerId(self.next_layer_id);
124 self.next_layer_id = self.next_layer_id.wrapping_add(1);
125 id
126 }
127
128 pub(crate) fn push_layer(&mut self, open: bool, blocks_lower: bool) -> InputLayer {
133 let id = self.mint_layer_id();
134 if open {
135 self.layers.push(LayerEntry { id, blocks_lower });
136 }
137 InputLayer { id }
138 }
139
140 pub(crate) fn register_handler(
142 &mut self,
143 layer: Option<LayerId>,
144 priority: EventPriority,
145 options: EventOptions,
146 area: Rc<Cell<Rect>>,
147 f: Box<dyn FnMut(Event) -> EventResult>,
148 ) {
149 let order = self.handlers.len();
150 self.handlers.push(HandlerEntry {
151 layer,
152 priority,
153 order,
154 options,
155 area,
156 f,
157 });
158 }
159
160 pub(crate) fn dispatch(&mut self, event: Event) {
167 let cut = self
169 .layers
170 .iter()
171 .rposition(|e| e.blocks_lower)
172 .unwrap_or(0);
173 let active: HashMap<LayerId, usize> = self.layers[cut..]
175 .iter()
176 .enumerate()
177 .map(|(off, e)| (e.id, cut + off))
178 .collect();
179
180 let mut handlers = std::mem::take(&mut self.handlers);
182
183 let mut global_idx: Vec<usize> = (0..handlers.len())
185 .filter(|&i| handlers[i].layer.is_none())
186 .collect();
187 global_idx.sort_by(|&a, &b| {
188 handlers[b]
189 .priority
190 .cmp(&handlers[a].priority)
191 .then(handlers[a].order.cmp(&handlers[b].order))
192 });
193 if Self::run_handlers(&mut handlers, &global_idx, &event) {
194 return;
195 }
196
197 let mut layer_idx: Vec<usize> = (0..handlers.len())
199 .filter(|&i| handlers[i].layer.is_some_and(|l| active.contains_key(&l)))
200 .collect();
201 layer_idx.sort_by(|&a, &b| {
202 let za = active[&handlers[a].layer.unwrap()];
203 let zb = active[&handlers[b].layer.unwrap()];
204 zb.cmp(&za) .then(handlers[b].priority.cmp(&handlers[a].priority)) .then(handlers[a].order.cmp(&handlers[b].order)) });
208 Self::run_handlers(&mut handlers, &layer_idx, &event);
209 }
211
212 fn run_handlers(handlers: &mut [HandlerEntry], order: &[usize], event: &Event) -> bool {
215 for &i in order {
216 if Self::call_handler(&mut handlers[i], event) == EventResult::Consumed {
217 return true;
218 }
219 }
220 false
221 }
222
223 fn call_handler(h: &mut HandlerEntry, event: &Event) -> EventResult {
226 if h.options.hit_test
227 && let Event::Mouse(m) = event
228 {
229 let a = h.area.get();
230 let hit = m.column >= a.x
231 && m.column < a.x.saturating_add(a.width)
232 && m.row >= a.y
233 && m.row < a.y.saturating_add(a.height);
234 if !hit {
235 return EventResult::Ignored;
236 }
237 }
238 (h.f)(event.clone())
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245 use crossterm::event::{
246 KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
247 };
248 use std::cell::RefCell;
249
250 type Log = Rc<RefCell<Vec<&'static str>>>;
251
252 fn key() -> Event {
253 Event::Key(KeyEvent::new(KeyCode::Char('x'), KeyModifiers::NONE))
254 }
255
256 fn mouse_at(col: u16, row: u16) -> Event {
257 Event::Mouse(MouseEvent {
258 kind: MouseEventKind::Down(MouseButton::Left),
259 column: col,
260 row,
261 modifiers: KeyModifiers::NONE,
262 })
263 }
264
265 fn full_area() -> Rc<Cell<Rect>> {
266 Rc::new(Cell::new(Rect::new(0, 0, 100, 100)))
267 }
268
269 fn handler(
270 log: &Log,
271 tag: &'static str,
272 result: EventResult,
273 ) -> Box<dyn FnMut(Event) -> EventResult> {
274 let log = log.clone();
275 Box::new(move |_| {
276 log.borrow_mut().push(tag);
277 result
278 })
279 }
280
281 fn opts(hit_test: bool) -> EventOptions {
282 EventOptions { hit_test }
283 }
284
285 #[test]
287 fn blocks_lower_truncates_background() {
288 let log: Log = Default::default();
289 let mut rt = InputRuntime::default();
290 rt.begin_frame();
291 let root = rt.root_layer();
292 rt.register_handler(
293 Some(root),
294 EventPriority::Normal,
295 opts(false),
296 full_area(),
297 handler(&log, "bg", EventResult::Ignored),
298 );
299 let modal = rt.push_layer(true, true);
300 rt.register_handler(
301 Some(modal.id),
302 EventPriority::Normal,
303 opts(false),
304 full_area(),
305 handler(&log, "modal", EventResult::Ignored),
306 );
307 rt.dispatch(key());
308 assert_eq!(*log.borrow(), ["modal"]);
309 }
310
311 #[test]
313 fn nested_blocks_lower_activates_only_top() {
314 let log: Log = Default::default();
315 let mut rt = InputRuntime::default();
316 rt.begin_frame();
317 let root = rt.root_layer();
318 rt.register_handler(
319 Some(root),
320 EventPriority::Normal,
321 opts(false),
322 full_area(),
323 handler(&log, "root", EventResult::Ignored),
324 );
325 let l1 = rt.push_layer(true, true);
326 rt.register_handler(
327 Some(l1.id),
328 EventPriority::Normal,
329 opts(false),
330 full_area(),
331 handler(&log, "l1", EventResult::Ignored),
332 );
333 let l2 = rt.push_layer(true, true);
334 rt.register_handler(
335 Some(l2.id),
336 EventPriority::Normal,
337 opts(false),
338 full_area(),
339 handler(&log, "l2", EventResult::Ignored),
340 );
341 rt.dispatch(key());
342 assert_eq!(*log.borrow(), ["l2"]);
343 }
344
345 #[test]
347 fn non_blocking_layers_above_blocker_remain_active() {
348 let log: Log = Default::default();
349 let mut rt = InputRuntime::default();
350 rt.begin_frame();
351 let root = rt.root_layer();
352 rt.register_handler(
353 Some(root),
354 EventPriority::Normal,
355 opts(false),
356 full_area(),
357 handler(&log, "root", EventResult::Ignored),
358 );
359 let modal = rt.push_layer(true, true);
360 rt.register_handler(
361 Some(modal.id),
362 EventPriority::Normal,
363 opts(false),
364 full_area(),
365 handler(&log, "modal", EventResult::Ignored),
366 );
367 let toast = rt.push_layer(true, false);
368 rt.register_handler(
369 Some(toast.id),
370 EventPriority::Normal,
371 opts(false),
372 full_area(),
373 handler(&log, "toast", EventResult::Ignored),
374 );
375
376 rt.dispatch(key());
377 assert_eq!(*log.borrow(), ["toast", "modal"]);
378 }
379
380 #[test]
382 fn consumed_stops_subsequent() {
383 let log: Log = Default::default();
384 let mut rt = InputRuntime::default();
385 rt.begin_frame();
386 let root = rt.root_layer();
387 rt.register_handler(
388 Some(root),
389 EventPriority::Normal,
390 opts(false),
391 full_area(),
392 handler(&log, "first", EventResult::Consumed),
393 );
394 rt.register_handler(
395 Some(root),
396 EventPriority::Normal,
397 opts(false),
398 full_area(),
399 handler(&log, "second", EventResult::Ignored),
400 );
401 rt.dispatch(key());
402 assert_eq!(*log.borrow(), ["first"]);
403 }
404
405 #[test]
407 fn ignored_continues_propagation() {
408 let log: Log = Default::default();
409 let mut rt = InputRuntime::default();
410 rt.begin_frame();
411 let root = rt.root_layer();
412 rt.register_handler(
413 Some(root),
414 EventPriority::Normal,
415 opts(false),
416 full_area(),
417 handler(&log, "first", EventResult::Ignored),
418 );
419 rt.register_handler(
420 Some(root),
421 EventPriority::Normal,
422 opts(false),
423 full_area(),
424 handler(&log, "second", EventResult::Ignored),
425 );
426 rt.dispatch(key());
427 assert_eq!(*log.borrow(), ["first", "second"]);
428 }
429
430 #[test]
432 fn layer_z_order_beats_priority() {
433 let log: Log = Default::default();
434 let mut rt = InputRuntime::default();
435 rt.begin_frame();
436 let root = rt.root_layer();
437 rt.register_handler(
438 Some(root),
439 EventPriority::High,
440 opts(false),
441 full_area(),
442 handler(&log, "bg_high", EventResult::Ignored),
443 );
444 let top = rt.push_layer(true, false); rt.register_handler(
446 Some(top.id),
447 EventPriority::Normal,
448 opts(false),
449 full_area(),
450 handler(&log, "top_normal", EventResult::Ignored),
451 );
452 rt.dispatch(key());
453 assert_eq!(*log.borrow(), ["top_normal", "bg_high"]);
454 }
455
456 #[test]
458 fn global_phase_first_and_can_consume() {
459 let log: Log = Default::default();
460 let mut rt = InputRuntime::default();
461 rt.begin_frame();
462 let root = rt.root_layer();
463 rt.register_handler(
464 None,
465 EventPriority::Normal,
466 opts(false),
467 full_area(),
468 handler(&log, "global", EventResult::Consumed),
469 );
470 rt.register_handler(
471 Some(root),
472 EventPriority::High,
473 opts(false),
474 full_area(),
475 handler(&log, "layer", EventResult::Ignored),
476 );
477 rt.dispatch(key());
478 assert_eq!(*log.borrow(), ["global"]);
479 }
480
481 #[test]
483 fn global_ignored_does_not_truncate() {
484 let log: Log = Default::default();
485 let mut rt = InputRuntime::default();
486 rt.begin_frame();
487 let root = rt.root_layer();
488 rt.register_handler(
489 None,
490 EventPriority::Normal,
491 opts(false),
492 full_area(),
493 handler(&log, "global", EventResult::Ignored),
494 );
495 rt.register_handler(
496 Some(root),
497 EventPriority::Normal,
498 opts(false),
499 full_area(),
500 handler(&log, "layer", EventResult::Ignored),
501 );
502 rt.dispatch(key());
503 assert_eq!(*log.borrow(), ["global", "layer"]);
504 }
505
506 #[test]
508 fn inactive_layer_handler_skipped() {
509 let log: Log = Default::default();
510 let mut rt = InputRuntime::default();
511 rt.begin_frame();
512 let inactive = rt.push_layer(false, true); rt.register_handler(
514 Some(inactive.id),
515 EventPriority::Normal,
516 opts(false),
517 full_area(),
518 handler(&log, "inactive", EventResult::Ignored),
519 );
520 rt.dispatch(key());
521 assert!(log.borrow().is_empty());
522 }
523
524 #[test]
526 fn hit_test_skips_outside_area() {
527 let log: Log = Default::default();
528 let mut rt = InputRuntime::default();
529 rt.begin_frame();
530 let root = rt.root_layer();
531 let area = Rc::new(Cell::new(Rect::new(0, 0, 10, 10)));
532 rt.register_handler(
533 Some(root),
534 EventPriority::Normal,
535 opts(true),
536 area,
537 handler(&log, "hit", EventResult::Consumed),
538 );
539 rt.dispatch(mouse_at(50, 50)); assert!(log.borrow().is_empty());
541
542 rt.begin_frame(); let root2 = rt.root_layer();
544 let area2 = Rc::new(Cell::new(Rect::new(0, 0, 10, 10)));
545 rt.register_handler(
546 Some(root2),
547 EventPriority::Normal,
548 opts(true),
549 area2,
550 handler(&log, "hit", EventResult::Consumed),
551 );
552 rt.dispatch(mouse_at(5, 5)); assert_eq!(*log.borrow(), ["hit"]);
554 }
555}