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 flag.set(true);
237 flag.set_gained(true);
238 flag.call_on_gained();
239 focus_debug!(self.core, " -> done");
240 }
241 }
242
243 /// Change to focus to the widget at the given position.
244 ///
245 /// This changes the focus and the gained/lost flags.
246 /// If this ends up with the same widget as before
247 /// gained and lost flags are not set.
248 ///
249 /// If the current widget has a [Navigation::Lock], this will
250 /// do nothing.
251 #[inline(always)]
252 pub fn focus_at(&self, col: u16, row: u16) -> bool {
253 focus_debug!(self.core, "focus at {},{}", col, row);
254 match self.navigation() {
255 Some(Navigation::Lock) => {
256 focus_debug!(self.core, " -> locked");
257 false
258 }
259 _ => self.core.focus_at(col, row),
260 }
261 }
262
263 /// Reset the mouse-focus flag to __true__.
264 #[inline(always)]
265 pub fn reset_mouse_focus(&self) -> bool {
266 self.core.reset_mouse_focus()
267 }
268
269 /// Set the mouse-focus to the given position.
270 ///
271 /// The top-most widget with a matching area will have
272 /// its mouse_focus flag set. Any containers
273 /// with an associated area that matches, will get
274 /// their mouse_focus flag set too.
275 #[inline(always)]
276 pub fn mouse_focus(&self, col: u16, row: u16) -> bool {
277 focus_debug!(self.core, "mouse-focus {} {}", col, row);
278 self.core.mouse_focus(col, row)
279 }
280
281 /// Focus the next widget in the cycle.
282 ///
283 /// This function will use the [Navigation] of the current widget
284 /// and only focus the next widget if it is `Leave`, `ReachLeaveBack` or
285 /// `Regular`.
286 ///
287 /// If no field has the focus the first navigable one gets it.
288 /// Sets the focus, gained and lost flags. If this ends up with
289 /// the same widget as before focus, gained and lost flag are not set.
290 #[inline]
291 pub fn next(&self) -> bool {
292 match self.navigation() {
293 None => {
294 self.first();
295 true
296 }
297 Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
298 focus_debug!(
299 self.core,
300 "next after {:?}",
301 self.core
302 .focused()
303 .map(|v| v.name())
304 .unwrap_or("None".into())
305 );
306 self.core.next()
307 }
308 v => {
309 focus_debug!(
310 self.core,
311 "next after {:?}, but navigation says {:?}",
312 self.core
313 .focused()
314 .map(|v| v.name().to_string())
315 .unwrap_or("None".into()),
316 v
317 );
318 false
319 }
320 }
321 }
322
323 /// Focus the previous widget in the cycle.
324 ///
325 /// This function will use the [Navigation] of the current widget
326 /// and only focus the next widget if it is `Leave`, `ReachLeaveFront` or
327 /// `Regular`.
328 ///
329 /// If no field has the focus the first navigable one gets it.
330 /// Sets the focus, gained and lost flags. If this ends up with
331 /// the same widget as before focus, gained and lost flag are not set.
332 #[inline]
333 pub fn prev(&self) -> bool {
334 match self.navigation() {
335 None => {
336 self.first();
337 true
338 }
339 Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
340 focus_debug!(
341 self.core,
342 "prev before {:?}",
343 self.core
344 .focused()
345 .map(|v| v.name().to_string())
346 .unwrap_or("None".into())
347 );
348 self.core.prev()
349 }
350 v => {
351 focus_debug!(
352 self.core,
353 "prev before {:?}, but navigation says {:?}",
354 self.core
355 .focused()
356 .map(|v| v.name().to_string())
357 .unwrap_or("None".into()),
358 v
359 );
360 false
361 }
362 }
363 }
364
365 /// Focus the next widget in the cycle.
366 ///
367 /// Applies some extra force to this action and allows
368 /// leaving widgets that have [Navigation] `Reach` and `ReachLeaveFront`
369 /// in addition to the regular `Leave`, `ReachLeaveBack` or
370 /// `Regular`.
371 ///
372 /// If no field has the focus the first navigable one gets it.
373 ///
374 /// Sets the focus, gained and lost flags. If this ends up with
375 /// the same widget as before focus, gained and lost flag are not set.
376 #[inline]
377 pub fn next_force(&self) -> bool {
378 match self.navigation() {
379 None => {
380 self.first();
381 true
382 }
383 Some(
384 Navigation::Leave
385 | Navigation::Reach
386 | Navigation::ReachLeaveFront
387 | Navigation::ReachLeaveBack
388 | Navigation::Regular,
389 ) => {
390 focus_debug!(
391 self.core,
392 "force next after {:?}",
393 self.core.focused().map(|v| v.name().to_string())
394 );
395 self.core.next()
396 }
397 v => {
398 focus_debug!(
399 self.core,
400 "force next after {:?}, but navigation says {:?}",
401 self.core.focused().map(|v| v.name().to_string()),
402 v
403 );
404 false
405 }
406 }
407 }
408
409 /// Focus the previous widget in the cycle.
410 ///
411 /// Applies some extra force to this action and allows
412 /// leaving widgets that have [Navigation] `Reach` and `ReachLeaveBack`
413 /// in addition to the regular `Leave`, `ReachLeaveFront` or
414 /// `Regular`.
415 ///
416 /// If no field has the focus the first navigable one gets it.
417 ///
418 /// Sets the focus, gained and lost flags. If this ends up with
419 /// the same widget as before focus, gained and lost flag are not set.
420 #[inline]
421 pub fn prev_force(&self) -> bool {
422 match self.navigation() {
423 None => {
424 self.first();
425 true
426 }
427 Some(
428 Navigation::Leave
429 | Navigation::Reach
430 | Navigation::ReachLeaveFront
431 | Navigation::ReachLeaveBack
432 | Navigation::Regular,
433 ) => {
434 focus_debug!(
435 self.core,
436 "force prev before {:?}",
437 self.core.focused().map(|v| v.name().to_string())
438 );
439 self.core.prev()
440 }
441 v => {
442 focus_debug!(
443 self.core,
444 "force prev before {:?}, but navigation says {:?}",
445 self.core.focused().map(|v| v.name().to_string()),
446 v
447 );
448 false
449 }
450 }
451 }
452
453 /// Is this widget part of this focus-cycle?
454 #[inline(always)]
455 pub fn is_valid_widget(&self, widget_state: &'_ dyn HasFocus) -> bool {
456 self.core.is_widget(&widget_state.focus())
457 }
458
459 /// Is this a container that is part of this focus-cycle?
460 #[inline(always)]
461 pub fn is_valid_container(&self, widget_state: &'_ dyn HasFocus) -> bool {
462 self.core.is_container(&widget_state.focus())
463 }
464
465 /// Returns the focused widget as FocusFlag.
466 ///
467 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
468 /// will be nicer.
469 #[inline(always)]
470 pub fn focused(&self) -> Option<FocusFlag> {
471 self.core.focused()
472 }
473
474 /// Returns the focused widget as widget-id.
475 ///
476 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
477 /// will be nicer.
478 #[inline(always)]
479 pub fn focused_widget_id(&self) -> Option<usize> {
480 self.core.focused().map(|v| v.id())
481 }
482
483 /// Returns the debug name of the focused widget.
484 #[inline(always)]
485 pub fn focused_name(&self) -> Option<String> {
486 self.core.focused().map(|v| v.name().to_string())
487 }
488
489 /// Returns the [Navigation] flag for the focused widget.
490 #[inline(always)]
491 pub fn navigation(&self) -> Option<Navigation> {
492 self.core.navigation()
493 }
494
495 /// Returns the widget that lost the focus as FocusFlag.
496 ///
497 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
498 /// will be nicer.
499 #[inline(always)]
500 pub fn lost_focus(&self) -> Option<FocusFlag> {
501 self.core.lost_focus()
502 }
503
504 /// Returns the widget that gained the focus as FocusFlag.
505 ///
506 /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
507 /// will be nicer.
508 #[inline(always)]
509 pub fn gained_focus(&self) -> Option<FocusFlag> {
510 self.core.gained_focus()
511 }
512
513 /// Sets the focus to the given widget, but doesn't set
514 /// lost and gained. This can be used to prevent any side
515 /// effects that use the gained/lost state.
516 ///
517 /// This changes the focus and the gained/lost flags.
518 /// If this ends up with the same widget as before
519 /// gained and lost flags are not set.
520 ///
521 /// This will ignore the [Navigation] flag of the
522 /// currently focused widget.
523 ///
524 /// You can also use a container-widget for this.
525 /// It will set the focus to the first widget of the
526 /// container.
527 #[inline]
528 pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
529 focus_debug!(self.core, "focus no_lost {:?}", widget_state.focus().name());
530 let flag = widget_state.focus();
531 if self.core.is_widget(&flag) {
532 if let Some(n) = self.core.index_of(&flag) {
533 self.core.focus_idx(n, false);
534 } else {
535 panic!(" => invalid widget");
536 }
537 } else if self.core.is_container(&flag) {
538 self.core.first_container(&flag);
539 } else {
540 focus_fail!(self.core, " => not a valid widget");
541 }
542 }
543
544 /// This expels the focus from the given widget/container.
545 ///
546 /// This is sometimes useful to set the focus to **somewhere else**.
547 /// This is especially useful when used for a container-widget that will
548 /// be hidden. Ensures there is still some widget with focus afterward.
549 ///
550 /// It will try to set the focus to the next widget or the
551 /// next widget following the container. If this ends up within
552 /// the given container it will set the focus to none.
553 ///
554 /// This function doesn't use the Navigation of the current widget.
555 #[inline]
556 pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
557 focus_debug!(
558 self.core,
559 "expel from widget {:?}",
560 widget_state.focus().name()
561 );
562 let flag = widget_state.focus();
563 if self.core.is_widget(&flag) {
564 if self.core.index_of(&flag).is_some() {
565 if widget_state.is_focused() {
566 self.core.next();
567 if widget_state.is_focused() {
568 focus_debug!(self.core, " -> no other focus, cleared");
569 flag.clear();
570 } else {
571 focus_debug!(self.core, " -> expelled");
572 }
573 } else {
574 focus_debug!(self.core, " => widget not focused");
575 }
576 } else {
577 panic!(" => invalid widget");
578 }
579 } else if self.core.is_container(&flag) {
580 if flag.is_focused() {
581 self.core.expel_container(flag);
582 } else {
583 focus_debug!(self.core, " => container not focused");
584 }
585 } else {
586 focus_fail!(self.core, " => not a valid widget");
587 }
588 }
589
590 /// Dynamic change of the widget structure for a container widget.
591 ///
592 /// This is only necessary if your widget structure changes
593 /// during event-handling, and you need a programmatic
594 /// focus-change for the new structure.
595 ///
596 /// This resets the focus-flags of the removed container.
597 pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
598 focus_debug!(
599 self.core,
600 "focus remove container {:?} ",
601 container.focus().name()
602 );
603 let flag = container.focus();
604 if self.core.is_container(&flag) {
605 if let Some((cidx, _)) = self.core.container_index_of(&flag) {
606 self.core.remove_container(cidx).reset();
607 focus_debug!(self.core, " -> removed");
608 } else {
609 panic!(" => invalid container?");
610 }
611 } else {
612 focus_fail!(self.core, " => no container flag");
613 }
614 }
615
616 /// Dynamic change of the widget structure for a container.
617 ///
618 /// This is only necessary if your widget structure changes
619 /// during event-handling, and you need a programmatic
620 /// focus-change for the new structure.
621 ///
622 /// If the widget that currently has the focus is still
623 /// part of the widget structure it keeps the focus.
624 /// The focus-flags for all widgets that are no longer part
625 /// of the widget structure are reset.
626 pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
627 focus_debug!(
628 self.core,
629 "focus update container {:?} ",
630 container.focus().name()
631 );
632 let flag = container.focus();
633 if self.core.is_container(&flag) {
634 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
635 let removed = self.core.remove_container(cidx);
636
637 let mut b = FocusBuilder::new(Some(Focus {
638 last: Default::default(),
639 core: removed,
640 }));
641 b.widget(container);
642 let insert = b.build();
643
644 self.core.insert_container(range.start, cidx, insert.core);
645
646 focus_debug!(self.core, " -> updated");
647 } else {
648 panic!(" => invalid container?");
649 }
650 } else {
651 focus_fail!(self.core, " => no container flag");
652 }
653 }
654
655 /// Dynamic change of the widget structure of a container.
656 ///
657 /// This is only necessary if your widget structure changes
658 /// during event-handling, and you need a programmatic
659 /// focus-change.
660 ///
661 /// This removes the widgets of one container and inserts
662 /// the widgets of the other one in place.
663 ///
664 /// If the widget that currently has the focus is still
665 /// part of the widget structure it keeps the focus.
666 /// The focus-flags for all widgets that are no longer part
667 /// of the widget structure are reset.
668 pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
669 focus_debug!(
670 self.core,
671 "focus replace container {:?} with {:?} ",
672 container.focus().name(),
673 new.focus().name()
674 );
675 let flag = container.focus();
676 if self.core.is_container(&flag) {
677 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
678 let removed = self.core.remove_container(cidx);
679
680 let mut b = FocusBuilder::new(Some(Focus {
681 last: Default::default(),
682 core: removed,
683 }));
684 b.widget(new);
685 let insert = b.build();
686
687 self.core.insert_container(range.start, cidx, insert.core);
688
689 focus_debug!(self.core, " -> replaced");
690 } else {
691 panic!(" => invalid container");
692 }
693 } else {
694 focus_fail!(self.core, " => no container flag");
695 }
696 }
697
698 /// Reset lost + gained flags.
699 ///
700 /// This is done automatically during event-handling.
701 /// Lost+Gained flags will only be set while handling
702 /// the original event that made the focus-change.
703 /// The next event, whatever it is, will reset these flags.
704 #[inline(always)]
705 pub fn reset_lost_gained(&self) {
706 self.core.reset_lost_gained();
707 }
708
709 /// Debug destructuring.
710 #[allow(clippy::type_complexity)]
711 pub fn clone_destruct(
712 &self,
713 ) -> (
714 Vec<FocusFlag>,
715 Vec<bool>,
716 Vec<(Rect, u16)>,
717 Vec<Navigation>,
718 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
719 ) {
720 self.core.clone_destruct()
721 }
722}
723
724impl HandleEvent<Event, Regular, Outcome> for Focus {
725 #[inline(always)]
726 fn handle(&mut self, event: &Event, _keymap: Regular) -> Outcome {
727 match event {
728 ct_event!(keycode press Tab) => {
729 focus_debug!(
730 self.core,
731 "Tab {:?}",
732 self.focused().map(|v| v.name().to_string())
733 );
734 let r = if self.next() {
735 Outcome::Changed
736 } else {
737 Outcome::Continue
738 };
739 focus_debug!(
740 self.core,
741 " -> {:?} {:?}",
742 r,
743 self.focused().map(|v| v.name().to_string())
744 );
745 r
746 }
747 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
748 focus_debug!(
749 self.core,
750 "BackTab {:?}",
751 self.focused().map(|v| v.name().to_string())
752 );
753 let r = if self.prev() {
754 Outcome::Changed
755 } else {
756 Outcome::Continue
757 };
758 focus_debug!(
759 self.core,
760 " -> {:?} {:?}",
761 r,
762 self.focused().map(|v| v.name().to_string())
763 );
764 r
765 }
766 _ => self.handle(event, MouseOnly),
767 }
768 }
769}
770
771impl HandleEvent<Event, MouseOnly, Outcome> for Focus {
772 #[inline(always)]
773 fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> Outcome {
774 match event {
775 Event::Mouse(crossterm::event::MouseEvent {
776 kind: crossterm::event::MouseEventKind::Drag(_),
777 ..
778 }) => {
779 self.reset_mouse_focus();
780 }
781 Event::Mouse(crossterm::event::MouseEvent {
782 kind:
783 crossterm::event::MouseEventKind::Moved
784 | crossterm::event::MouseEventKind::Down(_)
785 | crossterm::event::MouseEventKind::Up(_)
786 | crossterm::event::MouseEventKind::ScrollDown
787 | crossterm::event::MouseEventKind::ScrollUp
788 | crossterm::event::MouseEventKind::ScrollLeft
789 | crossterm::event::MouseEventKind::ScrollRight,
790 column: c,
791 row: r,
792 ..
793 }) => {
794 self.mouse_focus(*c, *r);
795 }
796 _ => {}
797 };
798
799 match event {
800 ct_event!(mouse down Left for column, row) => {
801 if self.focus_at(*column, *row) {
802 Outcome::Changed
803 } else {
804 self.reset_lost_gained();
805 Outcome::Continue
806 }
807 }
808 _ => {
809 self.reset_lost_gained();
810 Outcome::Continue
811 }
812 }
813 }
814}
815
816/// Handle all events.
817#[inline(always)]
818pub fn handle_focus(focus: &mut Focus, event: &Event) -> Outcome {
819 HandleEvent::handle(focus, event, Regular)
820}