rat_focus/focus.rs
1use crate::core::FocusCore;
2use crate::{FocusBuilder, FocusFlag, HasFocus, Navigation};
3use rat_event::{HandleEvent, MouseOnly, Outcome, Regular, crossterm, ct_event};
4use ratatui_core::layout::Rect;
5use ratatui_crossterm::crossterm::event::Event;
6use std::ops::Range;
7
8/// Focus deals with all focus-related issues.
9///
10/// Use [FocusBuilder] to construct the current Focus.
11///
12/// This is usually quick enough to do it for each event.
13/// It has to be rebuilt if any area has changed, so
14/// rebuilding it after a render() is fine.
15#[derive(Default, Debug, Clone)]
16pub struct Focus {
17 pub(crate) last: FocusCore,
18 pub(crate) core: FocusCore,
19}
20
21macro_rules! focus_debug {
22 ($core:expr, $($arg:tt)+) => {
23 if $core.log.get() {
24 log::log!(log::Level::Debug, $($arg)+);
25 }
26 }
27}
28
29macro_rules! focus_fail {
30 ($core:expr, $($arg:tt)+) => {
31 if $core.log.get() {
32 log::log!(log::Level::Debug, $($arg)+);
33 }
34 if $core.insta_panic.get() {
35 panic!($($arg)+)
36 }
37 }
38}
39
40impl Focus {
41 /// Writes a log for each operation.
42 pub fn enable_log(&self) {
43 self.core.log.set(true);
44 self.last.log.set(true);
45 }
46
47 /// Writes a log for each operation.
48 pub fn disable_log(&self) {
49 self.core.log.set(false);
50 self.last.log.set(false);
51 }
52
53 /// Enable insta-panic if any function is called
54 /// with a widget that is not part of the Focus.
55 pub fn enable_panic(&self) {
56 self.core.insta_panic.set(true);
57 self.last.insta_panic.set(true);
58 }
59
60 /// Disable insta-panic.
61 pub fn disable_panic(&self) {
62 self.core.insta_panic.set(false);
63 self.last.insta_panic.set(false);
64 }
65
66 /// Sets the focus to the given widget and remembers
67 /// the previous focused widget. If the focus is
68 /// currently set to the given widget it sets the
69 /// focus back to the previous widget.
70 pub fn flip_focus(
71 &self,
72 widget_state: &'_ dyn HasFocus,
73 flip_focus: &'_ mut Option<FocusFlag>,
74 ) {
75 focus_debug!(
76 self.core,
77 "flip-focus {:?} {:?}",
78 widget_state.focus().name(),
79 flip_focus
80 );
81 let flag = widget_state.focus();
82 if self.core.is_widget(&flag) {
83 if flag.is_focused() {
84 if let Some(flip_focus) = flip_focus {
85 self.focus(flip_focus);
86 } else {
87 focus_fail!(self.core, " => no previous widget");
88 }
89 } else {
90 *flip_focus = self.focused();
91 self.focus(&flag);
92 }
93 } else if self.core.is_container(&flag) {
94 if flag.is_focused() {
95 if let Some(flip_focus) = flip_focus {
96 self.focus(flip_focus);
97 } else {
98 focus_fail!(self.core, " => no previous widget");
99 }
100 } else {
101 self.core.first_container(&flag);
102 }
103 } else {
104 focus_fail!(self.core, " => not a valid widget");
105 }
106 }
107
108 /// Sets the focus to the given widget.
109 ///
110 /// This changes the focus and the gained/lost flags.
111 /// If this ends up with the same widget as before
112 /// gained and lost flags are not set.
113 ///
114 /// This will ignore the [Navigation] flag of the
115 /// currently focused widget.
116 ///
117 /// You can also use a container-widget for this.
118 /// It will set the focus to the first navigable widget
119 /// of the container.
120 #[inline]
121 pub fn focus(&self, widget_state: &'_ dyn HasFocus) {
122 focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
123 let flag = widget_state.focus();
124 if self.core.is_widget(&flag) {
125 if let Some(n) = self.core.index_of(&flag) {
126 self.core.focus_idx(n, true);
127 } else {
128 panic!(" => invalid widget?");
129 }
130 } else if self.core.is_container(&flag) {
131 self.core.first_container(&flag);
132 } else {
133 focus_fail!(self.core, " => not a valid widget");
134 }
135 }
136
137 /// Sets the focus to the widget by its widget-id.
138 ///
139 /// This can be useful if you want to store references
140 /// to widgets in some extra subsystem and can't use
141 /// a clone of the FocusFlag for that.
142 ///
143 /// This changes the focus and the gained/lost flags.
144 /// If this ends up with the same widget as before
145 /// gained and lost flags are not set.
146 ///
147 /// This will ignore the [Navigation] flag of the
148 /// currently focused widget.
149 ///
150 /// You can also use a container-widget for this.
151 /// It will set the focus to the first widget of the
152 /// container.
153 #[inline]
154 pub fn by_widget_id(&self, widget_id: usize) {
155 let widget_state = self.core.find_widget_id(widget_id);
156 focus_debug!(self.core, "focus {:?} -> {:?}", widget_id, widget_state);
157 let Some(widget_state) = widget_state else {
158 return;
159 };
160
161 let flag = widget_state.focus();
162 if self.core.is_widget(&flag) {
163 if let Some(n) = self.core.index_of(&flag) {
164 self.core.focus_idx(n, true);
165 } else {
166 panic!(" => invalid widget");
167 }
168 } else if self.core.is_container(&flag) {
169 self.core.first_container(&flag);
170 } else {
171 focus_fail!(self.core, " => not a valid widget");
172 }
173 }
174
175 /// Set the focus to the first navigable widget.
176 ///
177 /// This changes the focus and the gained/lost flags.
178 /// If this ends up with the same widget as before
179 /// gained and lost flags are not set.
180 ///
181 /// This will ignore the [Navigation] flag of the
182 /// currently focused widget.
183 #[inline(always)]
184 pub fn first(&self) {
185 focus_debug!(self.core, "focus first");
186 self.core.first();
187 }
188
189 #[deprecated(since = "1.1.2", note = "use focus() instead")]
190 pub fn first_in(&self, container: &'_ dyn HasFocus) {
191 self.focus(container);
192 }
193
194 /// Clear the focus for all widgets.
195 ///
196 /// This will reset the focus, gained and lost flags for
197 /// all widgets.
198 #[inline(always)]
199 pub fn none(&self) {
200 focus_debug!(self.core, "focus none");
201 self.core.none();
202 focus_debug!(self.core, " -> done");
203 }
204
205 /// This widget will have the focus, but it is not
206 /// yet part of the focus cycle. And the focus cycle
207 /// can't be properly rebuilt at this point.
208 ///
209 /// If the widget *is* part of the focus this will do nothing.
210 ///
211 /// If the widget is a container, it will just set
212 /// the container-flag. If you want to set a future widget
213 /// and its container, call future() for the widget first,
214 /// then the container.
215 #[inline(always)]
216 pub fn future(&self, widget_state: &'_ dyn HasFocus) {
217 focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
218 let flag = widget_state.focus();
219 if self.core.is_widget(&flag) {
220 focus_fail!(
221 self.core,
222 " => widget is part of focus. use focus() instead"
223 );
224 } else if self.core.is_container(&flag) {
225 focus_debug!(self.core, "future container");
226 let had_focus = flag.get();
227 flag.set(true);
228 if !had_focus {
229 flag.set_gained(true);
230 flag.call_on_gained();
231 }
232 focus_debug!(self.core, " -> done");
233 } else {
234 focus_debug!(self.core, "future focus");
235 self.core.none();
236 let had_focus = flag.get();
237 flag.set(true);
238 if !had_focus {
239 flag.set_gained(true);
240 flag.call_on_gained();
241 }
242 focus_debug!(self.core, " -> done");
243 }
244 }
245
246 /// Change to focus to the widget at the given position.
247 ///
248 /// This changes the focus and the gained/lost flags.
249 /// If this ends up with the same widget as before
250 /// gained and lost flags are not set.
251 ///
252 /// If the current widget has a [Navigation::Lock], this will
253 /// do nothing.
254 #[inline(always)]
255 pub fn focus_at(&self, col: u16, row: u16) -> bool {
256 focus_debug!(self.core, "focus at {},{}", col, row);
257 match self.navigation() {
258 Some(Navigation::Lock) => {
259 focus_debug!(self.core, " -> locked");
260 false
261 }
262 _ => self.core.focus_at(col, row),
263 }
264 }
265
266 /// Reset the obscured flag to __false__.
267 #[inline(always)]
268 pub fn clear_obscured(&self) -> bool {
269 self.core.clear_obscured()
270 }
271
272 /// Sets the obscured state for the given position.
273 ///
274 /// Hit-tests all widgets for the given position and
275 /// sets obscured to false if the widget-area is hit
276 /// and there are no containers/widgets with a *higher*
277 /// z-index.
278 #[inline(always)]
279 pub fn find_obscured(&self, col: u16, row: u16) -> bool {
280 focus_debug!(self.core, "find_obscured {} {}", col, row);
281 self.core.find_obscured(col, row)
282 }
283
284 /// Focus the next widget in the cycle.
285 ///
286 /// This function will use the [Navigation] of the current widget
287 /// and only focus the next widget if it is `Leave`, `ReachLeaveBack` or
288 /// `Regular`.
289 ///
290 /// If no field has the focus the first navigable one gets it.
291 /// Sets the focus, gained and lost flags. If this ends up with
292 /// the same widget as before focus, gained and lost flag are not set.
293 #[inline]
294 pub fn next(&self) -> bool {
295 match self.navigation() {
296 None => {
297 self.first();
298 true
299 }
300 Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
301 focus_debug!(
302 self.core,
303 "next after {:?}",
304 self.core
305 .focused()
306 .map(|v| v.name())
307 .unwrap_or("None".into())
308 );
309 self.core.next()
310 }
311 v => {
312 focus_debug!(
313 self.core,
314 "next after {:?}, but navigation says {:?}",
315 self.core
316 .focused()
317 .map(|v| v.name().to_string())
318 .unwrap_or("None".into()),
319 v
320 );
321 false
322 }
323 }
324 }
325
326 /// Focus the previous widget in the cycle.
327 ///
328 /// This function will use the [Navigation] of the current widget
329 /// and only focus the next widget if it is `Leave`, `ReachLeaveFront` or
330 /// `Regular`.
331 ///
332 /// If no field has the focus the first navigable one gets it.
333 /// Sets the focus, gained and lost flags. If this ends up with
334 /// the same widget as before focus, gained and lost flag are not set.
335 #[inline]
336 pub fn prev(&self) -> bool {
337 match self.navigation() {
338 None => {
339 self.first();
340 true
341 }
342 Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
343 focus_debug!(
344 self.core,
345 "prev before {:?}",
346 self.core
347 .focused()
348 .map(|v| v.name().to_string())
349 .unwrap_or("None".into())
350 );
351 self.core.prev()
352 }
353 v => {
354 focus_debug!(
355 self.core,
356 "prev before {:?}, but navigation says {:?}",
357 self.core
358 .focused()
359 .map(|v| v.name().to_string())
360 .unwrap_or("None".into()),
361 v
362 );
363 false
364 }
365 }
366 }
367
368 /// Focus the next widget in the cycle.
369 ///
370 /// Applies some extra force to this action and allows
371 /// leaving widgets that have [Navigation] `Reach` and `ReachLeaveFront`
372 /// in addition to the regular `Leave`, `ReachLeaveBack` or
373 /// `Regular`.
374 ///
375 /// If no field has the focus the first navigable one gets it.
376 ///
377 /// Sets the focus, gained and lost flags. If this ends up with
378 /// the same widget as before focus, gained and lost flag are not set.
379 #[inline]
380 pub fn next_force(&self) -> bool {
381 match self.navigation() {
382 None => {
383 self.first();
384 true
385 }
386 Some(
387 Navigation::Leave
388 | Navigation::Reach
389 | Navigation::ReachLeaveFront
390 | Navigation::ReachLeaveBack
391 | Navigation::Regular,
392 ) => {
393 focus_debug!(
394 self.core,
395 "force next after {:?}",
396 self.core.focused().map(|v| v.name().to_string())
397 );
398 self.core.next()
399 }
400 v => {
401 focus_debug!(
402 self.core,
403 "force next after {:?}, but navigation says {:?}",
404 self.core.focused().map(|v| v.name().to_string()),
405 v
406 );
407 false
408 }
409 }
410 }
411
412 /// Focus the previous widget in the cycle.
413 ///
414 /// Applies some extra force to this action and allows
415 /// leaving widgets that have [Navigation] `Reach` and `ReachLeaveBack`
416 /// in addition to the regular `Leave`, `ReachLeaveFront` or
417 /// `Regular`.
418 ///
419 /// If no field has the focus the first navigable one gets it.
420 ///
421 /// Sets the focus, gained and lost flags. If this ends up with
422 /// the same widget as before focus, gained and lost flag are not set.
423 #[inline]
424 pub fn prev_force(&self) -> bool {
425 match self.navigation() {
426 None => {
427 self.first();
428 true
429 }
430 Some(
431 Navigation::Leave
432 | Navigation::Reach
433 | Navigation::ReachLeaveFront
434 | Navigation::ReachLeaveBack
435 | Navigation::Regular,
436 ) => {
437 focus_debug!(
438 self.core,
439 "force prev before {:?}",
440 self.core.focused().map(|v| v.name().to_string())
441 );
442 self.core.prev()
443 }
444 v => {
445 focus_debug!(
446 self.core,
447 "force prev before {:?}, but navigation says {:?}",
448 self.core.focused().map(|v| v.name().to_string()),
449 v
450 );
451 false
452 }
453 }
454 }
455
456 /// Is this widget part of this focus-cycle?
457 #[inline(always)]
458 pub fn is_valid_widget(&self, widget_state: &'_ dyn HasFocus) -> bool {
459 self.core.is_widget(&widget_state.focus())
460 }
461
462 /// Is this a container that is part of this focus-cycle?
463 #[inline(always)]
464 pub fn is_valid_container(&self, widget_state: &'_ dyn HasFocus) -> bool {
465 self.core.is_container(&widget_state.focus())
466 }
467
468 /// Returns the focused widget as FocusFlag.
469 ///
470 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
471 /// will be nicer.
472 #[inline(always)]
473 pub fn focused(&self) -> Option<FocusFlag> {
474 self.core.focused()
475 }
476
477 /// Returns the focused widget as widget-id.
478 ///
479 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
480 /// will be nicer.
481 #[inline(always)]
482 pub fn focused_widget_id(&self) -> Option<usize> {
483 self.core.focused().map(|v| v.id())
484 }
485
486 /// Returns the debug name of the focused widget.
487 #[inline(always)]
488 pub fn focused_name(&self) -> Option<String> {
489 self.core.focused().map(|v| v.name().to_string())
490 }
491
492 /// Returns the [Navigation] flag for the focused widget.
493 #[inline(always)]
494 pub fn navigation(&self) -> Option<Navigation> {
495 self.core.navigation()
496 }
497
498 /// Returns the widget that lost the focus as FocusFlag.
499 ///
500 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
501 /// will be nicer.
502 #[inline(always)]
503 pub fn lost_focus(&self) -> Option<FocusFlag> {
504 self.core.lost_focus()
505 }
506
507 /// Returns the widget that gained the focus as FocusFlag.
508 ///
509 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
510 /// will be nicer.
511 #[inline(always)]
512 pub fn gained_focus(&self) -> Option<FocusFlag> {
513 self.core.gained_focus()
514 }
515
516 /// Sets the focus to the given widget, but doesn't set
517 /// lost and gained. This can be used to prevent any side
518 /// effects that use the gained/lost state.
519 ///
520 /// This changes the focus and the gained/lost flags.
521 /// If this ends up with the same widget as before
522 /// gained and lost flags are not set.
523 ///
524 /// This will ignore the [Navigation] flag of the
525 /// currently focused widget.
526 ///
527 /// You can also use a container-widget for this.
528 /// It will set the focus to the first widget of the
529 /// container.
530 #[inline]
531 pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
532 focus_debug!(self.core, "focus no_lost {:?}", widget_state.focus().name());
533 let flag = widget_state.focus();
534 if self.core.is_widget(&flag) {
535 if let Some(n) = self.core.index_of(&flag) {
536 self.core.focus_idx(n, false);
537 } else {
538 panic!(" => invalid widget");
539 }
540 } else if self.core.is_container(&flag) {
541 self.core.first_container(&flag);
542 } else {
543 focus_fail!(self.core, " => not a valid widget");
544 }
545 }
546
547 /// This expels the focus from the given widget/container.
548 ///
549 /// This is sometimes useful to set the focus to **somewhere else**.
550 /// This is especially useful when used for a container-widget that will
551 /// be hidden. Ensures there is still some widget with focus afterward.
552 ///
553 /// It will try to set the focus to the next widget or the
554 /// next widget following the container. If this ends up within
555 /// the given container it will set the focus to none.
556 ///
557 /// This function doesn't use the Navigation of the current widget.
558 #[inline]
559 pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
560 focus_debug!(
561 self.core,
562 "expel from widget {:?}",
563 widget_state.focus().name()
564 );
565 let flag = widget_state.focus();
566 if self.core.is_widget(&flag) {
567 if self.core.index_of(&flag).is_some() {
568 if widget_state.is_focused() {
569 self.core.next();
570 if widget_state.is_focused() {
571 focus_debug!(self.core, " -> no other focus, cleared");
572 flag.clear();
573 } else {
574 focus_debug!(self.core, " -> expelled");
575 }
576 } else {
577 focus_debug!(self.core, " => widget not focused");
578 }
579 } else {
580 panic!(" => invalid widget");
581 }
582 } else if self.core.is_container(&flag) {
583 if flag.is_focused() {
584 self.core.expel_container(flag);
585 } else {
586 focus_debug!(self.core, " => container not focused");
587 }
588 } else {
589 focus_fail!(self.core, " => not a valid widget");
590 }
591 }
592
593 /// Dynamic change of the widget structure for a container widget.
594 ///
595 /// This is only necessary if your widget structure changes
596 /// during event-handling, and you need a programmatic
597 /// focus-change for the new structure.
598 ///
599 /// This resets the focus-flags of the removed container.
600 pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
601 focus_debug!(
602 self.core,
603 "focus remove container {:?} ",
604 container.focus().name()
605 );
606 let flag = container.focus();
607 if self.core.is_container(&flag) {
608 if let Some((cidx, _)) = self.core.container_index_of(&flag) {
609 self.core.remove_container(cidx).reset();
610 focus_debug!(self.core, " -> removed");
611 } else {
612 panic!(" => invalid container?");
613 }
614 } else {
615 focus_fail!(self.core, " => no container flag");
616 }
617 }
618
619 /// Dynamic change of the widget structure for a container.
620 ///
621 /// This is only necessary if your widget structure changes
622 /// during event-handling, and you need a programmatic
623 /// focus-change for the new structure.
624 ///
625 /// If the widget that currently has the focus is still
626 /// part of the widget structure it keeps the focus.
627 /// The focus-flags for all widgets that are no longer part
628 /// of the widget structure are reset.
629 pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
630 focus_debug!(
631 self.core,
632 "focus update container {:?} ",
633 container.focus().name()
634 );
635 let flag = container.focus();
636 if self.core.is_container(&flag) {
637 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
638 let removed = self.core.remove_container(cidx);
639
640 let mut b = FocusBuilder::new(Some(Focus {
641 last: Default::default(),
642 core: removed,
643 }));
644 b.widget(container);
645 let insert = b.build();
646
647 self.core.insert_container(range.start, cidx, insert.core);
648
649 focus_debug!(self.core, " -> updated");
650 } else {
651 panic!(" => invalid container?");
652 }
653 } else {
654 focus_fail!(self.core, " => no container flag");
655 }
656 }
657
658 /// Dynamic change of the widget structure of a container.
659 ///
660 /// This is only necessary if your widget structure changes
661 /// during event-handling, and you need a programmatic
662 /// focus-change.
663 ///
664 /// This removes the widgets of one container and inserts
665 /// the widgets of the other one in place.
666 ///
667 /// If the widget that currently has the focus is still
668 /// part of the widget structure it keeps the focus.
669 /// The focus-flags for all widgets that are no longer part
670 /// of the widget structure are reset.
671 pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
672 focus_debug!(
673 self.core,
674 "focus replace container {:?} with {:?} ",
675 container.focus().name(),
676 new.focus().name()
677 );
678 let flag = container.focus();
679 if self.core.is_container(&flag) {
680 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
681 let removed = self.core.remove_container(cidx);
682
683 let mut b = FocusBuilder::new(Some(Focus {
684 last: Default::default(),
685 core: removed,
686 }));
687 b.widget(new);
688 let insert = b.build();
689
690 self.core.insert_container(range.start, cidx, insert.core);
691
692 focus_debug!(self.core, " -> replaced");
693 } else {
694 panic!(" => invalid container");
695 }
696 } else {
697 focus_fail!(self.core, " => no container flag");
698 }
699 }
700
701 /// Reset lost + gained flags.
702 ///
703 /// This is done automatically during event-handling.
704 /// Lost+Gained flags will only be set while handling
705 /// the original event that made the focus-change.
706 /// The next event, whatever it is, will reset these flags.
707 #[inline(always)]
708 pub fn reset_lost_gained(&self) {
709 self.core.reset_lost_gained();
710 }
711
712 /// Debug destructuring.
713 #[allow(clippy::type_complexity)]
714 pub fn clone_destruct(
715 &self,
716 ) -> (
717 Vec<FocusFlag>,
718 Vec<bool>,
719 Vec<(Rect, u16)>,
720 Vec<Navigation>,
721 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
722 ) {
723 self.core.clone_destruct()
724 }
725}
726
727impl HandleEvent<Event, Regular, Outcome> for Focus {
728 #[inline(always)]
729 fn handle(&mut self, event: &Event, _keymap: Regular) -> Outcome {
730 match event {
731 ct_event!(keycode press Tab) => {
732 focus_debug!(
733 self.core,
734 "Tab {:?}",
735 self.focused().map(|v| v.name().to_string())
736 );
737 let r = if self.next() {
738 Outcome::Changed
739 } else {
740 Outcome::Continue
741 };
742 focus_debug!(
743 self.core,
744 " -> {:?} {:?}",
745 r,
746 self.focused().map(|v| v.name().to_string())
747 );
748 r
749 }
750 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
751 focus_debug!(
752 self.core,
753 "BackTab {:?}",
754 self.focused().map(|v| v.name().to_string())
755 );
756 let r = if self.prev() {
757 Outcome::Changed
758 } else {
759 Outcome::Continue
760 };
761 focus_debug!(
762 self.core,
763 " -> {:?} {:?}",
764 r,
765 self.focused().map(|v| v.name().to_string())
766 );
767 r
768 }
769 _ => self.handle(event, MouseOnly),
770 }
771 }
772}
773
774impl HandleEvent<Event, MouseOnly, Outcome> for Focus {
775 #[inline(always)]
776 fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> Outcome {
777 match event {
778 Event::Mouse(crossterm::event::MouseEvent {
779 kind: crossterm::event::MouseEventKind::Drag(_),
780 ..
781 }) => {
782 self.clear_obscured();
783 }
784 Event::Mouse(crossterm::event::MouseEvent {
785 kind:
786 crossterm::event::MouseEventKind::Moved
787 | crossterm::event::MouseEventKind::Down(_)
788 | crossterm::event::MouseEventKind::Up(_)
789 | crossterm::event::MouseEventKind::ScrollDown
790 | crossterm::event::MouseEventKind::ScrollUp
791 | crossterm::event::MouseEventKind::ScrollLeft
792 | crossterm::event::MouseEventKind::ScrollRight,
793 column: c,
794 row: r,
795 ..
796 }) => {
797 self.find_obscured(*c, *r);
798 }
799 _ => {}
800 };
801
802 match event {
803 ct_event!(mouse down Left for column, row) => {
804 if self.focus_at(*column, *row) {
805 Outcome::Changed
806 } else {
807 self.reset_lost_gained();
808 Outcome::Continue
809 }
810 }
811 _ => {
812 self.reset_lost_gained();
813 Outcome::Continue
814 }
815 }
816 }
817}
818
819/// Handle all events.
820#[inline(always)]
821pub fn handle_focus(focus: &mut Focus, event: &Event) -> Outcome {
822 HandleEvent::handle(focus, event, Regular)
823}