rat_focus/
focus.rs

1use crate::focus::core::FocusCore;
2use crate::{FocusFlag, HasFocus, Navigation};
3pub use core::FocusBuilder;
4use rat_event::{HandleEvent, MouseOnly, Outcome, Regular, ct_event};
5use ratatui::layout::Rect;
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    last: FocusCore,
18    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.
67    ///
68    /// This changes the focus and the gained/lost flags.
69    /// If this ends up with the same widget as before
70    /// gained and lost flags are not set.
71    ///
72    /// This will ignore the [Navigation] flag of the
73    /// currently focused widget.
74    ///
75    /// You can also use a container-widget for this.
76    /// It will set the focus to the first navigable widget
77    /// of the container.
78    #[inline]
79    pub fn focus(&self, widget_state: &'_ dyn HasFocus) {
80        focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
81        let flag = widget_state.focus();
82        if self.core.is_widget(&flag) {
83            if let Some(n) = self.core.index_of(&flag) {
84                self.core.focus_idx(n, true);
85            } else {
86                panic!("    => invalid widget?");
87            }
88        } else if self.core.is_container(&flag) {
89            self.core.first_container(&flag);
90        } else {
91            focus_fail!(self.core, "    => not a valid widget");
92        }
93    }
94
95    /// Sets the focus to the widget by its widget-id.
96    ///
97    /// This can be useful if you want to store references
98    /// to widgets in some extra subsystem and can't use
99    /// a clone of the FocusFlag for that.
100    ///
101    /// This changes the focus and the gained/lost flags.
102    /// If this ends up with the same widget as before
103    /// gained and lost flags are not set.
104    ///
105    /// This will ignore the [Navigation] flag of the
106    /// currently focused widget.
107    ///
108    /// You can also use a container-widget for this.
109    /// It will set the focus to the first widget of the
110    /// container.
111    #[inline]
112    pub fn by_widget_id(&self, widget_id: usize) {
113        let widget_state = self.core.find_widget_id(widget_id);
114        focus_debug!(self.core, "focus {:?} -> {:?}", widget_id, widget_state);
115        let Some(widget_state) = widget_state else {
116            return;
117        };
118
119        let flag = widget_state.focus();
120        if self.core.is_widget(&flag) {
121            if let Some(n) = self.core.index_of(&flag) {
122                self.core.focus_idx(n, true);
123            } else {
124                panic!("    => invalid widget");
125            }
126        } else if self.core.is_container(&flag) {
127            self.core.first_container(&flag);
128        } else {
129            focus_fail!(self.core, "    => not a valid widget");
130        }
131    }
132
133    /// Set the focus to the first navigable widget.
134    ///
135    /// This changes the focus and the gained/lost flags.
136    /// If this ends up with the same widget as before
137    /// gained and lost flags are not set.
138    ///
139    /// This will ignore the [Navigation] flag of the
140    /// currently focused widget.
141    #[inline(always)]
142    pub fn first(&self) {
143        focus_debug!(self.core, "focus first");
144        self.core.first();
145    }
146
147    #[deprecated(since = "1.1.2", note = "use focus() instead")]
148    pub fn first_in(&self, container: &'_ dyn HasFocus) {
149        self.focus(container);
150    }
151
152    /// Clear the focus for all widgets.
153    ///
154    /// This will reset the focus, gained and lost flags for
155    /// all widgets.
156    #[inline(always)]
157    pub fn none(&self) {
158        focus_debug!(self.core, "focus none");
159        self.core.none();
160        focus_debug!(self.core, "    -> done");
161    }
162
163    /// This widget will have the focus, but it is not
164    /// yet part of the focus cycle. And the focus cycle
165    /// can't be properly rebuilt at this point.
166    ///
167    /// If the widget *is* part of the focus this will
168    /// behave just like [focus].
169    ///
170    /// Caveat:
171    ///
172    /// If the widget will be in a container in the future,
173    /// the container-flag itself will not be set.
174    #[inline(always)]
175    pub fn future(&self, widget_state: &'_ dyn HasFocus) {
176        focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
177        let flag = widget_state.focus();
178        if self.core.is_widget(&flag) {
179            if let Some(n) = self.core.index_of(&flag) {
180                self.core.focus_idx(n, true);
181            } else {
182                panic!("    => invalid widget");
183            }
184        } else if self.core.is_container(&flag) {
185            self.core.first_container(&flag);
186        } else {
187            focus_debug!(self.core, "future focus");
188            self.core.none();
189            widget_state.focus().set(true);
190            widget_state.focus().set_gained(true);
191            focus_debug!(self.core, "    -> done");
192        }
193    }
194
195    /// Change to focus to the widget at the given position.
196    ///
197    /// This changes the focus and the gained/lost flags.
198    /// If this ends up with the same widget as before
199    /// gained and lost flags are not set.
200    ///
201    /// If the current widget has a [Navigation::Lock], this will
202    /// do nothing.
203    #[inline(always)]
204    pub fn focus_at(&self, col: u16, row: u16) -> bool {
205        focus_debug!(self.core, "focus at {},{}", col, row);
206        match self.navigation() {
207            Some(Navigation::Lock) => {
208                focus_debug!(self.core, "    -> locked");
209                false
210            }
211            _ => self.core.focus_at(col, row),
212        }
213    }
214
215    /// Focus the next widget in the cycle.
216    ///
217    /// This function will use the [Navigation] of the current widget
218    /// and only focus the next widget if it is `Leave`, `ReachLeaveBack` or
219    /// `Regular`.
220    ///
221    /// If no field has the focus the first navigable one gets it.
222    /// Sets the focus, gained and lost flags. If this ends up with
223    /// the same widget as before focus, gained and lost flag are not set.
224    #[inline]
225    pub fn next(&self) -> bool {
226        match self.navigation() {
227            None => {
228                self.first();
229                true
230            }
231            Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
232                focus_debug!(
233                    self.core,
234                    "next after {:?}",
235                    self.core
236                        .focused()
237                        .map(|v| v.name().to_string())
238                        .unwrap_or("None".into())
239                );
240                self.core.next()
241            }
242            v => {
243                focus_debug!(
244                    self.core,
245                    "next after {:?}, but navigation says {:?}",
246                    self.core
247                        .focused()
248                        .map(|v| v.name().to_string())
249                        .unwrap_or("None".into()),
250                    v
251                );
252                false
253            }
254        }
255    }
256
257    /// Focus the previous widget in the cycle.
258    ///
259    /// This function will use the [Navigation] of the current widget
260    /// and only focus the next widget if it is `Leave`, `ReachLeaveFront` or
261    /// `Regular`.
262    ///
263    /// If no field has the focus the first navigable one gets it.
264    /// Sets the focus, gained and lost flags. If this ends up with
265    /// the same widget as before focus, gained and lost flag are not set.
266    #[inline]
267    pub fn prev(&self) -> bool {
268        match self.navigation() {
269            None => {
270                self.first();
271                true
272            }
273            Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
274                focus_debug!(
275                    self.core,
276                    "prev before {:?}",
277                    self.core
278                        .focused()
279                        .map(|v| v.name().to_string())
280                        .unwrap_or("None".into())
281                );
282                self.core.prev()
283            }
284            v => {
285                focus_debug!(
286                    self.core,
287                    "prev before {:?}, but navigation says {:?}",
288                    self.core
289                        .focused()
290                        .map(|v| v.name().to_string())
291                        .unwrap_or("None".into()),
292                    v
293                );
294                false
295            }
296        }
297    }
298
299    /// Focus the next widget in the cycle.
300    ///
301    /// Applies some extra force to this action and allows
302    /// leaving widgets that have [Navigation] `Reach` and `ReachLeaveFront`
303    /// in addition to the regular `Leave`, `ReachLeaveBack` or
304    /// `Regular`.
305    ///
306    /// If no field has the focus the first navigable one gets it.
307    ///
308    /// Sets the focus, gained and lost flags. If this ends up with
309    /// the same widget as before focus, gained and lost flag are not set.
310    #[inline]
311    pub fn next_force(&self) -> bool {
312        match self.navigation() {
313            None => {
314                self.first();
315                true
316            }
317            Some(
318                Navigation::Leave
319                | Navigation::Reach
320                | Navigation::ReachLeaveFront
321                | Navigation::ReachLeaveBack
322                | Navigation::Regular,
323            ) => {
324                focus_debug!(
325                    self.core,
326                    "force next after {:?}",
327                    self.core.focused().map(|v| v.name().to_string())
328                );
329                self.core.next()
330            }
331            v => {
332                focus_debug!(
333                    self.core,
334                    "force next after {:?}, but navigation says {:?}",
335                    self.core.focused().map(|v| v.name().to_string()),
336                    v
337                );
338                false
339            }
340        }
341    }
342
343    /// Focus the previous widget in the cycle.
344    ///
345    /// Applies some extra force to this action and allows
346    /// leaving widgets that have [Navigation] `Reach` and `ReachLeaveBack`
347    /// in addition to the regular `Leave`, `ReachLeaveFront` or
348    /// `Regular`.
349    ///
350    /// If no field has the focus the first navigable one gets it.
351    ///
352    /// Sets the focus, gained and lost flags. If this ends up with
353    /// the same widget as before focus, gained and lost flag are not set.
354    #[inline]
355    pub fn prev_force(&self) -> bool {
356        match self.navigation() {
357            None => {
358                self.first();
359                true
360            }
361            Some(
362                Navigation::Leave
363                | Navigation::Reach
364                | Navigation::ReachLeaveFront
365                | Navigation::ReachLeaveBack
366                | Navigation::Regular,
367            ) => {
368                focus_debug!(
369                    self.core,
370                    "force prev before {:?}",
371                    self.core.focused().map(|v| v.name().to_string())
372                );
373                self.core.prev()
374            }
375            v => {
376                focus_debug!(
377                    self.core,
378                    "force prev before {:?}, but navigation says {:?}",
379                    self.core.focused().map(|v| v.name().to_string()),
380                    v
381                );
382                false
383            }
384        }
385    }
386
387    /// Is this widget part of this focus-cycle?
388    #[inline(always)]
389    pub fn is_valid_widget(&self, widget_state: &'_ dyn HasFocus) -> bool {
390        self.core.is_widget(&widget_state.focus())
391    }
392
393    /// Is this a container that is part of this focus-cycle?
394    #[inline(always)]
395    pub fn is_valid_container(&self, widget_state: &'_ dyn HasFocus) -> bool {
396        self.core.is_container(&widget_state.focus())
397    }
398
399    /// Returns the focused widget as FocusFlag.
400    ///
401    /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
402    /// will be nicer.
403    #[inline(always)]
404    pub fn focused(&self) -> Option<FocusFlag> {
405        self.core.focused()
406    }
407
408    /// Returns the focused widget as widget-id.
409    ///
410    /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
411    /// will be nicer.
412    #[inline(always)]
413    pub fn focused_widget_id(&self) -> Option<usize> {
414        self.core.focused().map(|v| v.id())
415    }
416
417    /// Returns the debug name of the focused widget.
418    #[inline(always)]
419    pub fn focused_name(&self) -> Option<String> {
420        self.core.focused().map(|v| v.name().to_string())
421    }
422
423    /// Returns the [Navigation] flag for the focused widget.
424    #[inline(always)]
425    pub fn navigation(&self) -> Option<Navigation> {
426        self.core.navigation()
427    }
428
429    /// Returns the widget that lost the focus as FocusFlag.
430    ///
431    /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
432    /// will be nicer.
433    #[inline(always)]
434    pub fn lost_focus(&self) -> Option<FocusFlag> {
435        self.core.lost_focus()
436    }
437
438    /// Returns the widget that gained the focus as FocusFlag.
439    ///
440    /// For control-flow [crate::match_focus] or [crate::on_gained] or [crate::on_lost]
441    /// will be nicer.
442    #[inline(always)]
443    pub fn gained_focus(&self) -> Option<FocusFlag> {
444        self.core.gained_focus()
445    }
446
447    /// Sets the focus to the given widget, but doesn't set
448    /// lost and gained. This can be used to prevent any side
449    /// effects that use the gained/lost state.
450    ///
451    /// This changes the focus and the gained/lost flags.
452    /// If this ends up with the same widget as before
453    /// gained and lost flags are not set.
454    ///
455    /// This will ignore the [Navigation] flag of the
456    /// currently focused widget.
457    ///
458    /// You can also use a container-widget for this.
459    /// It will set the focus to the first widget of the
460    /// container.
461    #[inline]
462    pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
463        focus_debug!(self.core, "focus no_lost {:?}", widget_state.focus().name());
464        let flag = widget_state.focus();
465        if self.core.is_widget(&flag) {
466            if let Some(n) = self.core.index_of(&flag) {
467                self.core.focus_idx(n, false);
468            } else {
469                panic!("    => invalid widget");
470            }
471        } else if self.core.is_container(&flag) {
472            self.core.first_container(&flag);
473        } else {
474            focus_fail!(self.core, "    => not a valid widget");
475        }
476    }
477
478    /// This expels the focus from the given widget/container.
479    ///
480    /// This is sometimes useful to set the focus to **somewhere else**.
481    /// This is especially useful when used for a container-widget that will
482    /// be hidden. Ensures there is still some widget with focus afterward.
483    ///
484    /// It will try to set the focus to the next widget or the
485    /// next widget following the container. If this ends up within
486    /// the given container it will set the focus to none.
487    ///
488    /// This function doesn't use the Navigation of the current widget.
489    #[inline]
490    pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
491        focus_debug!(
492            self.core,
493            "expel from widget {:?}",
494            widget_state.focus().name()
495        );
496        let flag = widget_state.focus();
497        if self.core.is_widget(&flag) {
498            if self.core.index_of(&flag).is_some() {
499                if widget_state.is_focused() {
500                    self.core.next();
501                    if widget_state.is_focused() {
502                        focus_debug!(self.core, "    -> no other focus, cleared");
503                        flag.clear();
504                    } else {
505                        focus_debug!(self.core, "    -> expelled");
506                    }
507                } else {
508                    focus_debug!(self.core, "    => widget not focused");
509                }
510            } else {
511                panic!("    => invalid widget");
512            }
513        } else if self.core.is_container(&flag) {
514            if flag.is_focused() {
515                self.core.expel_container(flag);
516            } else {
517                focus_debug!(self.core, "    => container not focused");
518            }
519        } else {
520            focus_fail!(self.core, "    => not a valid widget");
521        }
522    }
523
524    /// Dynamic change of the widget structure for a container widget.
525    ///
526    /// This is only necessary if your widget structure changes
527    /// during event-handling, and you need a programmatic
528    /// focus-change for the new structure.
529    ///
530    /// This resets the focus-flags of the removed container.
531    pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
532        focus_debug!(
533            self.core,
534            "focus remove container {:?} ",
535            container.focus().name()
536        );
537        let flag = container.focus();
538        if self.core.is_container(&flag) {
539            if let Some((cidx, _)) = self.core.container_index_of(&flag) {
540                self.core.remove_container(cidx).reset();
541                focus_debug!(self.core, "    -> removed");
542            } else {
543                panic!("    => invalid container?");
544            }
545        } else {
546            focus_fail!(self.core, "    => no container flag");
547        }
548    }
549
550    /// Dynamic change of the widget structure for a container.
551    ///
552    /// This is only necessary if your widget structure changes
553    /// during event-handling, and you need a programmatic
554    /// focus-change for the new structure.
555    ///
556    /// If the widget that currently has the focus is still
557    /// part of the widget structure it keeps the focus.
558    /// The focus-flags for all widgets that are no longer part
559    /// of the widget structure are reset.
560    pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
561        focus_debug!(
562            self.core,
563            "focus update container {:?} ",
564            container.focus().name()
565        );
566        let flag = container.focus();
567        if self.core.is_container(&flag) {
568            if let Some((cidx, range)) = self.core.container_index_of(&flag) {
569                let removed = self.core.remove_container(cidx);
570
571                let mut b = FocusBuilder::new(Some(Focus {
572                    last: Default::default(),
573                    core: removed,
574                }));
575                b.widget(container);
576                let insert = b.build();
577
578                self.core.insert_container(range.start, cidx, insert.core);
579
580                focus_debug!(self.core, "    -> updated");
581            } else {
582                panic!("    => invalid container?");
583            }
584        } else {
585            focus_fail!(self.core, "    => no container flag");
586        }
587    }
588
589    /// Dynamic change of the widget structure of a container.
590    ///
591    /// This is only necessary if your widget structure changes
592    /// during event-handling, and you need a programmatic
593    /// focus-change.
594    ///
595    /// This removes the widgets of one container and inserts
596    /// the widgets of the other one in place.
597    ///
598    /// If the widget that currently has the focus is still
599    /// part of the widget structure it keeps the focus.
600    /// The focus-flags for all widgets that are no longer part
601    /// of the widget structure are reset.
602    pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
603        focus_debug!(
604            self.core,
605            "focus replace container {:?} with {:?} ",
606            container.focus().name(),
607            new.focus().name()
608        );
609        let flag = container.focus();
610        if self.core.is_container(&flag) {
611            if let Some((cidx, range)) = self.core.container_index_of(&flag) {
612                let removed = self.core.remove_container(cidx);
613
614                let mut b = FocusBuilder::new(Some(Focus {
615                    last: Default::default(),
616                    core: removed,
617                }));
618                b.widget(new);
619                let insert = b.build();
620
621                self.core.insert_container(range.start, cidx, insert.core);
622
623                focus_debug!(self.core, "    -> replaced");
624            } else {
625                panic!("    => invalid container");
626            }
627        } else {
628            focus_fail!(self.core, "    => no container flag");
629        }
630    }
631
632    /// Reset lost + gained flags.
633    ///
634    /// This is done automatically during event-handling.
635    /// Lost+Gained flags will only be set while handling
636    /// the original event that made the focus-change.
637    /// The next event, whatever it is, will reset these flags.
638    #[inline(always)]
639    pub fn reset_lost_gained(&self) {
640        self.core.reset_lost_gained();
641    }
642
643    /// Debug destructuring.
644    #[allow(clippy::type_complexity)]
645    pub fn clone_destruct(
646        &self,
647    ) -> (
648        Vec<FocusFlag>,
649        Vec<bool>,
650        Vec<(Rect, u16)>,
651        Vec<Navigation>,
652        Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
653    ) {
654        self.core.clone_destruct()
655    }
656}
657
658mod core {
659    use crate::{Focus, FocusFlag, HasFocus, Navigation};
660    use fxhash::FxBuildHasher;
661    use ratatui::layout::Rect;
662    use std::cell::Cell;
663    use std::collections::HashSet;
664    use std::ops::Range;
665
666    /// Builder for the Focus.
667    #[derive(Debug, Default)]
668    pub struct FocusBuilder {
669        last: FocusCore,
670
671        log: Cell<bool>,
672        insta_panic: Cell<bool>,
673
674        // base z value.
675        // starting a container adds the z-value of the container
676        // to the z_base. closing the container subtracts from the
677        // z_base. any widgets added in between have a z-value
678        // of z_base + widget z-value.
679        //
680        // this enables clean stacking of containers/widgets.
681        z_base: u16,
682
683        // new core
684        focus_ids: HashSet<usize, FxBuildHasher>,
685        focus_flags: Vec<FocusFlag>,
686        duplicate: Vec<bool>,
687        areas: Vec<(Rect, u16)>,
688        navigable: Vec<Navigation>,
689        container_ids: HashSet<usize, FxBuildHasher>,
690        containers: Vec<(Container, Range<usize>)>,
691    }
692
693    impl FocusBuilder {
694        /// Create a new FocusBuilder.
695        ///
696        /// This can take the previous Focus and ensures that
697        /// widgets that are no longer part of the focus list
698        /// have their focus-flag cleared.
699        ///
700        /// It will also recycle the storage of the old Focus.
701        pub fn new(last: Option<Focus>) -> FocusBuilder {
702            if let Some(mut last) = last {
703                // clear any data but retain the allocation.
704                last.last.clear();
705
706                Self {
707                    last: last.core,
708                    log: Default::default(),
709                    insta_panic: Default::default(),
710                    z_base: 0,
711                    focus_ids: last.last.focus_ids,
712                    focus_flags: last.last.focus_flags,
713                    duplicate: last.last.duplicate,
714                    areas: last.last.areas,
715                    navigable: last.last.navigable,
716                    container_ids: last.last.container_ids,
717                    containers: last.last.containers,
718                }
719            } else {
720                Self {
721                    last: FocusCore::default(),
722                    log: Default::default(),
723                    insta_panic: Default::default(),
724                    z_base: Default::default(),
725                    focus_ids: Default::default(),
726                    focus_flags: Default::default(),
727                    duplicate: Default::default(),
728                    areas: Default::default(),
729                    navigable: Default::default(),
730                    container_ids: Default::default(),
731                    containers: Default::default(),
732                }
733            }
734        }
735
736        /// The same as build_for but with logs enabled.
737        pub fn log_build_for(container: &dyn HasFocus) -> Focus {
738            let mut b = FocusBuilder::new(None);
739            b.enable_log();
740            b.widget(container);
741            b.build()
742        }
743
744        /// Shortcut for building the focus for a container
745        /// that implements [HasFocus].
746        ///
747        /// This creates a fresh Focus.
748        ///
749        /// __See__
750        ///
751        /// Use [rebuild_for](FocusBuilder::rebuild_for) if you want
752        /// to ensure that widgets that are no longer in the widget
753        /// structure have their focus flag reset properly. If you
754        /// don't have some logic to conditionally add widgets to
755        /// the focus, this function is probably fine.
756        pub fn build_for(container: &dyn HasFocus) -> Focus {
757            let mut b = FocusBuilder::new(None);
758            b.widget(container);
759            b.build()
760        }
761
762        /// The same as rebuild_for but with logs enabled.
763        pub fn log_rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
764            let mut b = FocusBuilder::new(old);
765            b.enable_log();
766            b.widget(container);
767            b.build()
768        }
769
770        /// Shortcut function for building the focus for a container
771        /// that implements [HasFocus]
772        ///
773        /// This takes the old Focus and reuses most of its allocations.
774        /// It also ensures that any widgets no longer in the widget structure
775        /// have their focus-flags reset.
776        pub fn rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
777            let mut b = FocusBuilder::new(old);
778            b.widget(container);
779            b.build()
780        }
781
782        /// Do some logging of the build.
783        pub fn enable_log(&self) {
784            self.log.set(true);
785        }
786
787        /// Do some logging of the build.
788        pub fn disable_log(&self) {
789            self.log.set(false);
790        }
791
792        /// Enable insta-panic for certain failures.
793        pub fn enable_panic(&self) {
794            self.insta_panic.set(true);
795        }
796
797        /// Disable insta-panic for certain failures.
798        pub fn disable_panic(&self) {
799            self.insta_panic.set(false);
800        }
801
802        /// Add a widget by calling its `build` function.
803        pub fn widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
804            widget.build(self);
805            self
806        }
807
808        /// Add a widget by calling its build function.
809        ///
810        /// This tries to override the default navigation
811        /// for the given widget. This will fail if the
812        /// widget is a container. It may also fail
813        /// for other reasons. Depends on the widget.
814        ///
815        /// Enable log to check.
816        #[allow(clippy::collapsible_else_if)]
817        pub fn widget_navigate(
818            &mut self,
819            widget: &dyn HasFocus,
820            navigation: Navigation,
821        ) -> &mut Self {
822            widget.build(self);
823
824            let widget_flag = widget.focus();
825            // override navigation for the widget
826            if let Some(idx) = self.focus_flags.iter().position(|v| *v == widget_flag) {
827                focus_debug!(
828                    self,
829                    "override navigation for {:?} with {:?}",
830                    widget_flag,
831                    navigation
832                );
833
834                self.navigable[idx] = navigation;
835            } else {
836                if self.container_ids.contains(&widget_flag.widget_id()) {
837                    focus_fail!(
838                        self,
839                        "FAIL to override navigation for {:?}. This is a container.",
840                        widget_flag,
841                    );
842                } else {
843                    focus_fail!(
844                        self,
845                        "FAIL to override navigation for {:?}. Widget doesn't use this focus-flag",
846                        widget_flag,
847                    );
848                }
849            }
850
851            self
852        }
853
854        /// Add a bunch of widgets.
855        #[inline]
856        pub fn widgets<const N: usize>(&mut self, widgets: [&dyn HasFocus; N]) -> &mut Self {
857            for widget in widgets {
858                widget.build(self);
859            }
860            self
861        }
862
863        /// Start a container widget. Must be matched with
864        /// the equivalent [end](Self::end). Uses focus(), area() and
865        /// z_area() of the given container. navigable() is
866        /// currently not used, just leave it at the default.
867        ///
868        /// __Attention__
869        ///
870        /// Use the returned value when calling [end](Self::end).
871        ///
872        /// __Panic__
873        ///
874        /// Panics if the same container-flag is added twice.
875        #[must_use]
876        pub fn start(&mut self, container: &dyn HasFocus) -> FocusFlag {
877            self.start_with_flags(container.focus(), container.area(), container.area_z())
878        }
879
880        /// End a container widget.
881        pub fn end(&mut self, tag: FocusFlag) {
882            focus_debug!(self, "end container {:?}", tag);
883            assert!(self.container_ids.contains(&tag.widget_id()));
884
885            for (c, r) in self.containers.iter_mut().rev() {
886                if c.container_flag != tag {
887                    if !c.complete {
888                        panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
889                    }
890                } else {
891                    r.end = self.focus_flags.len();
892                    c.complete = true;
893
894                    focus_debug!(self, "container range {:?}", r);
895
896                    self.z_base -= c.delta_z;
897
898                    break;
899                }
900            }
901        }
902
903        /// Directly add the given widget's flags. Doesn't call
904        /// build() instead it uses focus(), etc. and appends a single widget.
905        ///
906        /// This is intended to be used when __implementing__
907        /// HasFocus::build() for a widget.
908        ///
909        /// In all other situations it's better to use [widget()](FocusBuilder::widget).
910        ///
911        /// __Panic__
912        ///
913        /// Panics if the same focus-flag is added twice.
914        pub fn leaf_widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
915            self.widget_with_flags(
916                widget.focus(),
917                widget.area(),
918                widget.area_z(),
919                widget.navigable(),
920            );
921            self
922        }
923
924        /// Manually add a widgets flags.
925        ///
926        /// This is intended to be used when __implementing__
927        /// HasFocus::build() for a widget.
928        ///
929        /// In all other situations it's better to use [widget()](FocusBuilder::widget).
930        ///
931        /// __Panic__
932        ///
933        /// Panics if the same focus-flag is added twice.
934        /// Except it is allowable to add the flag a second time with
935        /// Navigation::Mouse or Navigation::None
936        pub fn widget_with_flags(
937            &mut self,
938            focus: FocusFlag,
939            area: Rect,
940            area_z: u16,
941            navigable: Navigation,
942        ) {
943            let duplicate = self.focus_ids.contains(&focus.widget_id());
944
945            // there can be a second entry for the same focus-flag
946            // if it is only for mouse interactions.
947            if duplicate {
948                assert!(matches!(navigable, Navigation::Mouse | Navigation::None))
949            }
950
951            focus_debug!(self, "widget {:?}", focus);
952
953            self.focus_ids.insert(focus.widget_id());
954            self.focus_flags.push(focus);
955            self.duplicate.push(duplicate);
956            self.areas.push((area, self.z_base + area_z));
957            self.navigable.push(navigable);
958        }
959
960        /// Start a container widget.
961        ///
962        /// Returns the FocusFlag of the container. This flag must
963        /// be used to close the container with [end](Self::end).
964        ///
965        /// __Panic__
966        ///
967        /// Panics if the same container-flag is added twice.
968        #[must_use]
969        pub fn start_with_flags(
970            &mut self,
971            container_flag: FocusFlag,
972            area: Rect,
973            area_z: u16,
974        ) -> FocusFlag {
975            focus_debug!(self, "start container {:?}", container_flag);
976
977            // no duplicates allowed for containers.
978            assert!(!self.container_ids.contains(&container_flag.widget_id()));
979
980            self.z_base += area_z;
981
982            let len = self.focus_flags.len();
983            self.container_ids.insert(container_flag.widget_id());
984            self.containers.push((
985                Container {
986                    container_flag: container_flag.clone(),
987                    area: (area, self.z_base),
988                    delta_z: area_z,
989                    complete: false,
990                },
991                len..len,
992            ));
993
994            container_flag
995        }
996
997        /// Build the Focus.
998        ///
999        /// If the previous Focus is known, this will also
1000        /// reset the FocusFlag for any widget no longer part of
1001        /// the Focus.
1002        pub fn build(mut self) -> Focus {
1003            // cleanup outcasts.
1004            for v in &self.last.focus_flags {
1005                if !self.focus_ids.contains(&v.widget_id()) {
1006                    v.clear();
1007                }
1008            }
1009            for (v, _) in &self.last.containers {
1010                let have_container = self
1011                    .containers
1012                    .iter()
1013                    .any(|(c, _)| v.container_flag == c.container_flag);
1014                if !have_container {
1015                    v.container_flag.clear();
1016                }
1017            }
1018            self.last.clear();
1019
1020            // check new tree.
1021            for (c, _) in self.containers.iter_mut().rev() {
1022                if !c.complete {
1023                    panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
1024                }
1025            }
1026
1027            let log = self.last.log.get();
1028            let insta_panic = self.last.insta_panic.get();
1029
1030            Focus {
1031                last: self.last,
1032                core: FocusCore {
1033                    log: Cell::new(log),
1034                    insta_panic: Cell::new(insta_panic),
1035                    focus_ids: self.focus_ids,
1036                    focus_flags: self.focus_flags,
1037                    duplicate: self.duplicate,
1038                    areas: self.areas,
1039                    navigable: self.navigable,
1040                    container_ids: self.container_ids,
1041                    containers: self.containers,
1042                },
1043            }
1044        }
1045    }
1046
1047    /// Struct for the data of the focus-container itself.
1048    #[derive(Debug, Clone)]
1049    struct Container {
1050        /// Summarizes all the contained FocusFlags.
1051        /// If any of them has the focus set, this will be set too.
1052        /// This can help if you build compound widgets.
1053        container_flag: FocusFlag,
1054        /// Area for the whole compound.
1055        /// Contains the area and a z-value.
1056        area: (Rect, u16),
1057        /// Delta Z value compared to the enclosing container.
1058        delta_z: u16,
1059        /// Flag for construction.
1060        complete: bool,
1061    }
1062
1063    /// Focus core.
1064    #[derive(Debug, Default, Clone)]
1065    pub(super) struct FocusCore {
1066        /// Focus logging
1067        pub(super) log: Cell<bool>,
1068        pub(super) insta_panic: Cell<bool>,
1069
1070        /// List of focus-ids.
1071        focus_ids: HashSet<usize, FxBuildHasher>,
1072        /// List of flags.
1073        focus_flags: Vec<FocusFlag>,
1074        /// Is the flag the primary flag, or just a duplicate
1075        /// to allow for multiple areas.
1076        duplicate: Vec<bool>,
1077        /// Areas for each widget.
1078        /// Contains the area and a z-value for the area.
1079        areas: Vec<(Rect, u16)>,
1080        /// Keyboard navigable
1081        navigable: Vec<Navigation>,
1082        /// List of focus-ids.
1083        container_ids: HashSet<usize, FxBuildHasher>,
1084        /// List of containers and their dependencies.
1085        /// Range here is a range in the vecs above. The ranges are
1086        /// all disjoint or completely contained within one other.
1087        /// No criss-cross intersections.
1088        containers: Vec<(Container, Range<usize>)>,
1089    }
1090
1091    impl FocusCore {
1092        /// Clear.
1093        pub(super) fn clear(&mut self) {
1094            self.focus_ids.clear();
1095            self.focus_flags.clear();
1096            self.duplicate.clear();
1097            self.areas.clear();
1098            self.navigable.clear();
1099            self.container_ids.clear();
1100            self.containers.clear();
1101        }
1102
1103        /// Find the FocusFlag by widget_id
1104        pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
1105            self.focus_flags
1106                .iter()
1107                .find(|v| widget_id == v.widget_id())
1108                .cloned()
1109        }
1110
1111        /// Is a widget?
1112        pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
1113            self.focus_ids.contains(&focus_flag.widget_id())
1114        }
1115
1116        /// Find the first occurrence of the given focus-flag.
1117        pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
1118            self.focus_flags
1119                .iter()
1120                .enumerate()
1121                .find(|(_, f)| *f == focus_flag)
1122                .map(|(idx, _)| idx)
1123        }
1124
1125        /// Is a container
1126        pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
1127            self.container_ids.contains(&focus_flag.widget_id())
1128        }
1129
1130        /// Find the given container-flag in the list of sub-containers.
1131        pub(super) fn container_index_of(
1132            &self,
1133            container_flag: &FocusFlag,
1134        ) -> Option<(usize, Range<usize>)> {
1135            self.containers
1136                .iter()
1137                .enumerate()
1138                .find(|(_, (c, _))| &c.container_flag == container_flag)
1139                .map(|(idx, (_, range))| (idx, range.clone()))
1140        }
1141
1142        /// Append a container.
1143        ///
1144        /// * pos - position inside the focus-flags
1145        /// * cpos - position inside the sub-containers
1146        pub(super) fn insert_container(
1147            &mut self,
1148            idx: usize,
1149            cidx: usize,
1150            mut container: FocusCore,
1151        ) {
1152            for c in &self.focus_flags {
1153                for d in &container.focus_flags {
1154                    assert_ne!(c, d);
1155                }
1156            }
1157
1158            // range for the data of the added container.
1159            let start = idx;
1160            let end = idx + container.focus_flags.len();
1161
1162            self.focus_ids.extend(container.focus_ids.iter());
1163            self.focus_flags
1164                .splice(idx..idx, container.focus_flags.drain(..));
1165            self.duplicate
1166                .splice(idx..idx, container.duplicate.drain(..));
1167            self.areas.splice(idx..idx, container.areas.drain(..));
1168            self.navigable
1169                .splice(idx..idx, container.navigable.drain(..));
1170
1171            // expand current ranges
1172            for (_, r) in &mut self.containers {
1173                *r = Self::expand(start..end, r.clone());
1174            }
1175            // shift inserted ranges into place
1176            self.containers.splice(
1177                cidx..cidx,
1178                container
1179                    .containers
1180                    .drain(..)
1181                    .map(|(c, r)| (c, Self::shift(start, r))),
1182            );
1183            self.container_ids.extend(container.container_ids.iter());
1184        }
1185
1186        /// Remove everything for the given container.
1187        /// Return the extracted values as FocusCore.
1188        pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1189            let crange = self.containers[cidx].1.clone();
1190
1191            // remove
1192            let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1193            let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1194            for f in focus_flags.iter() {
1195                self.focus_ids.remove(&f.widget_id());
1196                focus_ids.insert(f.widget_id());
1197            }
1198            let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1199            let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1200            let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1201            let sub_containers = self
1202                .containers
1203                .iter()
1204                .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1205                .cloned()
1206                .collect::<Vec<_>>();
1207            // remove the container and all sub-containers in the range.
1208            self.containers
1209                .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1210            let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1211            for (sc, _) in sub_containers.iter() {
1212                self.container_ids.remove(&sc.container_flag.widget_id());
1213                sub_container_ids.insert(sc.container_flag.widget_id());
1214            }
1215
1216            // adjust the remaining sub-containers
1217            for (_, r) in &mut self.containers {
1218                *r = Self::shrink(crange.start..crange.end, r.clone());
1219            }
1220
1221            FocusCore {
1222                log: Cell::new(false),
1223                insta_panic: Cell::new(false),
1224                focus_ids,
1225                focus_flags,
1226                duplicate,
1227                areas,
1228                navigable,
1229                container_ids: sub_container_ids,
1230                containers: sub_containers,
1231            }
1232        }
1233
1234        // shift the ranges left by n
1235        fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1236            range.start + n..range.end + n
1237        }
1238
1239        // expand the range caused by insert
1240        fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1241            let len = insert.end - insert.start;
1242
1243            if range.start >= insert.start {
1244                range.start += len;
1245            }
1246            if range.end > insert.start {
1247                range.end += len;
1248            }
1249            range
1250        }
1251
1252        // shrink the range caused by remove
1253        fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1254            let len = remove.end - remove.start;
1255
1256            if range.start < remove.start {
1257                // leave
1258            } else if range.start >= remove.start && range.start <= remove.end {
1259                range.start = remove.start;
1260            } else {
1261                range.start -= len;
1262            }
1263
1264            if range.end < remove.start {
1265                // leave
1266            } else if range.end >= remove.start && range.end <= remove.end {
1267                range.end = remove.start;
1268            } else {
1269                range.end -= len;
1270            }
1271
1272            range
1273        }
1274
1275        /// Reset the flags for a new round.
1276        /// set_lost - copy the current focus to the lost flag.
1277        fn __start_change(&self, set_lost: bool) {
1278            for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1279                if *duplicate {
1280                    // skip duplicates
1281                    continue;
1282                }
1283                if set_lost {
1284                    f.set_lost(f.get());
1285                } else {
1286                    f.set_lost(false);
1287                }
1288                f.set_gained(false);
1289                f.set(false);
1290            }
1291        }
1292
1293        /// Set the focus to this index. Doesn't touch
1294        /// other flags.
1295        fn __focus(&self, n: usize, set_lost: bool) -> bool {
1296            if let Some(f) = self.focus_flags.get(n) {
1297                focus_debug!(self, "    -> focus {}:{:?}", n, f.name());
1298                f.set(true);
1299                if set_lost {
1300                    if f.lost() {
1301                        // new focus same as old.
1302                        // reset lost + gained
1303                        f.set_lost(false);
1304                        f.set_gained(false);
1305                        false
1306                    } else {
1307                        f.set_gained(true);
1308                        true
1309                    }
1310                } else {
1311                    false
1312                }
1313            } else {
1314                false
1315            }
1316        }
1317
1318        /// Accumulate all container flags.
1319        #[allow(clippy::collapsible_if)]
1320        fn __accumulate(&self) {
1321            for (n, f) in self.focus_flags.iter().enumerate() {
1322                if f.gained() && !self.duplicate[n] {
1323                    if let Some(on_gained_cb) = f.0.on_gained.borrow().as_ref() {
1324                        focus_debug!(self, "    -> notify_on_gained {}:{:?}", n, f.name());
1325                        on_gained_cb();
1326                    }
1327                }
1328                if f.lost() && !self.duplicate[n] {
1329                    if let Some(on_lost_cb) = f.0.on_lost.borrow().as_ref() {
1330                        focus_debug!(self, "    -> notify_on_lost {}:{:?}", n, f.name());
1331                        on_lost_cb();
1332                    }
1333                }
1334            }
1335
1336            for (f, r) in &self.containers {
1337                let mut any_gained = false;
1338                let mut any_lost = false;
1339                let mut any_focused = false;
1340
1341                for idx in r.clone() {
1342                    any_gained |= self.focus_flags[idx].gained();
1343                    any_lost |= self.focus_flags[idx].lost();
1344                    any_focused |= self.focus_flags[idx].get();
1345                }
1346
1347                f.container_flag.set(any_focused);
1348                f.container_flag.set_lost(any_lost && !any_gained);
1349                if any_lost && !any_gained {
1350                    if let Some(on_lost_cb) = f.container_flag.0.on_lost.borrow().as_ref() {
1351                        focus_debug!(
1352                            self,
1353                            "-> notify_on_lost container {:?}",
1354                            f.container_flag.name()
1355                        );
1356                        on_lost_cb();
1357                    }
1358                }
1359                f.container_flag.set_gained(any_gained && !any_lost);
1360                if any_gained && !any_lost {
1361                    if let Some(on_gained_cb) = f.container_flag.0.on_gained.borrow().as_ref() {
1362                        focus_debug!(
1363                            self,
1364                            "-> notify_on_gained container {:?}",
1365                            f.container_flag.name()
1366                        );
1367                        on_gained_cb();
1368                    }
1369                }
1370            }
1371        }
1372
1373        /// Reset all lost+gained+focus flags.
1374        pub(super) fn reset(&self) {
1375            for f in self.focus_flags.iter() {
1376                f.set(false);
1377                f.set_lost(false);
1378                f.set_gained(false);
1379            }
1380            for (f, _) in self.containers.iter() {
1381                f.container_flag.set(false);
1382                f.container_flag.set_gained(false);
1383                f.container_flag.set_lost(false);
1384            }
1385        }
1386
1387        /// Reset all lost+gained flags.
1388        pub(super) fn reset_lost_gained(&self) {
1389            for f in self.focus_flags.iter() {
1390                f.set_lost(false);
1391                f.set_gained(false);
1392            }
1393            for (f, _) in self.containers.iter() {
1394                f.container_flag.set_gained(false);
1395                f.container_flag.set_lost(false);
1396            }
1397        }
1398
1399        /// Set the initial focus.
1400        pub(super) fn first(&self) {
1401            if let Some(n) = self.first_navigable(0) {
1402                self.__start_change(true);
1403                self.__focus(n, true);
1404                self.__accumulate();
1405            } else {
1406                focus_debug!(self, "    -> no navigable widget");
1407            }
1408        }
1409
1410        /// Clear the focus.
1411        pub(super) fn none(&self) {
1412            self.__start_change(true);
1413            self.__accumulate();
1414        }
1415
1416        /// Set the initial focus.
1417        pub(super) fn first_container(&self, container: &FocusFlag) {
1418            if let Some((_idx, range)) = self.container_index_of(container) {
1419                if let Some(n) = self.first_navigable(range.start) {
1420                    if n < range.end {
1421                        self.__start_change(true);
1422                        self.__focus(n, true);
1423                        self.__accumulate();
1424                    } else {
1425                        focus_debug!(self, "    -> no navigable widget for container");
1426                    }
1427                } else {
1428                    focus_debug!(self, "    -> no navigable widget");
1429                }
1430            } else {
1431                focus_fail!(self, "    => container not found");
1432            }
1433        }
1434
1435        /// Set the focus at the given index.
1436        pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1437            self.__start_change(set_lost);
1438            self.__focus(n, set_lost);
1439            self.__accumulate();
1440        }
1441
1442        /// Set the focus at the given screen position.
1443        /// Traverses the list to find the matching widget.
1444        /// Checks the area and the z-areas.
1445        pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1446            let pos = (col, row).into();
1447
1448            enum ZOrder {
1449                Widget(usize),
1450                Container(usize),
1451            }
1452
1453            // find any matching areas
1454            let mut z_order: Option<(ZOrder, u16)> = None;
1455            // search containers first. the widgets inside have the same z and are
1456            // more specific, so they should override.
1457            for (idx, (sub, _)) in self.containers.iter().enumerate() {
1458                if sub.area.0.contains(pos) {
1459                    focus_debug!(
1460                        self,
1461                        "    container area-match {:?}",
1462                        sub.container_flag.name()
1463                    );
1464
1465                    z_order = if let Some(zz) = z_order {
1466                        if zz.1 <= sub.area.1 {
1467                            Some((ZOrder::Container(idx), sub.area.1))
1468                        } else {
1469                            Some(zz)
1470                        }
1471                    } else {
1472                        Some((ZOrder::Container(idx), sub.area.1))
1473                    };
1474                }
1475            }
1476            // search widgets
1477            for (idx, area) in self.areas.iter().enumerate() {
1478                if area.0.contains(pos) {
1479                    focus_debug!(self, "    area-match {:?}", self.focus_flags[idx].name());
1480
1481                    z_order = if let Some(zz) = z_order {
1482                        if zz.1 <= area.1 {
1483                            Some((ZOrder::Widget(idx), area.1))
1484                        } else {
1485                            Some(zz)
1486                        }
1487                    } else {
1488                        Some((ZOrder::Widget(idx), area.1))
1489                    };
1490                }
1491            }
1492
1493            // process in order, last is on top if more than one.
1494            if let Some((idx, _)) = z_order {
1495                match idx {
1496                    ZOrder::Widget(idx) => {
1497                        if self.navigable[idx] != Navigation::None {
1498                            self.__start_change(true);
1499                            let r = self.__focus(idx, true);
1500                            self.__accumulate();
1501                            return r;
1502                        } else {
1503                            focus_debug!(
1504                                self,
1505                                "    -> not mouse reachable {:?}",
1506                                self.focus_flags[idx].name()
1507                            );
1508                            return false;
1509                        }
1510                    }
1511                    ZOrder::Container(idx) => {
1512                        let range = &self.containers[idx].1;
1513                        if let Some(n) = self.first_navigable(range.start) {
1514                            self.__start_change(true);
1515                            let r = self.__focus(n, true);
1516                            self.__accumulate();
1517                            return r;
1518                        }
1519                    }
1520                }
1521            }
1522
1523            // last is on top
1524            focus_debug!(self, "    -> no widget at pos");
1525
1526            false
1527        }
1528
1529        /// Expel focus from the given container.
1530        pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1531            if let Some((_idx, range)) = self.container_index_of(&flag) {
1532                self.__start_change(true);
1533                let n = self.next_navigable(range.end);
1534                self.__focus(n, true);
1535                self.__accumulate();
1536
1537                // still focused?
1538                if flag.is_focused() {
1539                    focus_debug!(self, "    -> focus not usable. cleared");
1540                    self.none();
1541                } else {
1542                    focus_debug!(self, "    -> expelled.");
1543                }
1544                true
1545            } else {
1546                focus_fail!(self, "    => container not found");
1547                false
1548            }
1549        }
1550
1551        /// Focus next.
1552        pub(super) fn next(&self) -> bool {
1553            self.__start_change(true);
1554            for (n, p) in self.focus_flags.iter().enumerate() {
1555                if p.lost() {
1556                    let n = self.next_navigable(n);
1557                    self.__focus(n, true);
1558                    self.__accumulate();
1559                    return true;
1560                }
1561            }
1562            if let Some(n) = self.first_navigable(0) {
1563                focus_debug!(
1564                    self,
1565                    "    use first_navigable {}:{:?}",
1566                    n,
1567                    self.focus_flags[n].name()
1568                );
1569                self.__focus(n, true);
1570                self.__accumulate();
1571                return true;
1572            }
1573            focus_debug!(self, "    -> no next");
1574            false
1575        }
1576
1577        /// Focus prev.
1578        pub(super) fn prev(&self) -> bool {
1579            self.__start_change(true);
1580            for (i, p) in self.focus_flags.iter().enumerate() {
1581                if p.lost() {
1582                    let n = self.prev_navigable(i);
1583                    self.__focus(n, true);
1584                    self.__accumulate();
1585                    return true;
1586                }
1587            }
1588            if let Some(n) = self.first_navigable(0) {
1589                focus_debug!(
1590                    self,
1591                    "    use first_navigable {}:{:?}",
1592                    n,
1593                    self.focus_flags[n].name()
1594                );
1595                self.__focus(n, true);
1596                self.__accumulate();
1597                return true;
1598            }
1599            focus_debug!(self, "    -> no prev");
1600            false
1601        }
1602
1603        /// Returns the navigation flag for the focused widget.
1604        pub(super) fn navigation(&self) -> Option<Navigation> {
1605            self.focus_flags
1606                .iter()
1607                .enumerate()
1608                .find(|(_, v)| v.get())
1609                .map(|(i, _)| self.navigable[i])
1610        }
1611
1612        /// Currently focused.
1613        pub(super) fn focused(&self) -> Option<FocusFlag> {
1614            self.focus_flags.iter().find(|v| v.get()).cloned()
1615        }
1616
1617        /// Last lost focus.
1618        pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1619            self.focus_flags.iter().find(|v| v.lost()).cloned()
1620        }
1621
1622        /// Current gained focus.
1623        pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1624            self.focus_flags.iter().find(|v| v.gained()).cloned()
1625        }
1626
1627        /// First navigable flag starting at n.
1628        fn first_navigable(&self, start: usize) -> Option<usize> {
1629            focus_debug!(
1630                self,
1631                "first navigable, start at {}:{:?} ",
1632                start,
1633                if start < self.focus_flags.len() {
1634                    self.focus_flags[start].name()
1635                } else {
1636                    "beginning"
1637                }
1638            );
1639            for n in start..self.focus_flags.len() {
1640                if matches!(
1641                    self.navigable[n],
1642                    Navigation::Reach
1643                        | Navigation::ReachLeaveBack
1644                        | Navigation::ReachLeaveFront
1645                        | Navigation::Regular
1646                ) {
1647                    focus_debug!(self, "    -> {}:{:?}", n, self.focus_flags[n].name());
1648                    return Some(n);
1649                }
1650            }
1651            focus_debug!(self, "    -> no first");
1652            None
1653        }
1654
1655        /// Next navigable flag, starting at start.
1656        fn next_navigable(&self, start: usize) -> usize {
1657            focus_debug!(
1658                self,
1659                "next navigable after {}:{:?}",
1660                start,
1661                if start < self.focus_flags.len() {
1662                    self.focus_flags[start].name()
1663                } else {
1664                    "last"
1665                }
1666            );
1667
1668            let mut n = start;
1669            loop {
1670                n = if n + 1 < self.focus_flags.len() {
1671                    n + 1
1672                } else {
1673                    0
1674                };
1675                if matches!(
1676                    self.navigable[n],
1677                    Navigation::Reach
1678                        | Navigation::ReachLeaveBack
1679                        | Navigation::ReachLeaveFront
1680                        | Navigation::Regular
1681                ) {
1682                    focus_debug!(self, "    -> {}:{:?}", n, self.focus_flags[n].name());
1683                    return n;
1684                }
1685                if n == start {
1686                    focus_debug!(self, "    -> {}:end at start", n);
1687                    return n;
1688                }
1689            }
1690        }
1691
1692        /// Previous navigable flag, starting at start.
1693        fn prev_navigable(&self, start: usize) -> usize {
1694            focus_debug!(
1695                self,
1696                "prev navigable before {}:{:?}",
1697                start,
1698                self.focus_flags[start].name()
1699            );
1700
1701            let mut n = start;
1702            loop {
1703                n = if n > 0 {
1704                    n - 1
1705                } else {
1706                    self.focus_flags.len() - 1
1707                };
1708                if matches!(
1709                    self.navigable[n],
1710                    Navigation::Reach
1711                        | Navigation::ReachLeaveBack
1712                        | Navigation::ReachLeaveFront
1713                        | Navigation::Regular
1714                ) {
1715                    focus_debug!(self, "    -> {}:{:?}", n, self.focus_flags[n].name());
1716                    return n;
1717                }
1718                if n == start {
1719                    focus_debug!(self, "    -> {}:end at start", n);
1720                    return n;
1721                }
1722            }
1723        }
1724
1725        /// Debug destructuring.
1726        #[allow(clippy::type_complexity)]
1727        pub(super) fn clone_destruct(
1728            &self,
1729        ) -> (
1730            Vec<FocusFlag>,
1731            Vec<bool>,
1732            Vec<(Rect, u16)>,
1733            Vec<Navigation>,
1734            Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1735        ) {
1736            (
1737                self.focus_flags.clone(),
1738                self.duplicate.clone(),
1739                self.areas.clone(),
1740                self.navigable.clone(),
1741                self.containers
1742                    .iter()
1743                    .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1744                    .collect::<Vec<_>>(),
1745            )
1746        }
1747    }
1748
1749    #[cfg(test)]
1750    mod test {
1751        use crate::focus::core::FocusCore;
1752        use crate::{FocusBuilder, FocusFlag, HasFocus};
1753        use ratatui::layout::Rect;
1754
1755        #[test]
1756        fn test_change() {
1757            assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1758            assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1759
1760            assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1761            assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1762            assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1763            assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1764            assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1765
1766            assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1767            assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1768            assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1769            assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1770            assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1771
1772            assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1773            assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1774            assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1775            assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1776            assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1777
1778            assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1779            assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1780            assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1781            assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1782            assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1783        }
1784
1785        #[test]
1786        #[should_panic]
1787        fn test_double_insert() {
1788            let a = FocusFlag::named("a");
1789            let b = FocusFlag::named("b");
1790
1791            let mut fb = FocusBuilder::new(None);
1792            fb.widget(&a);
1793            fb.widget(&b);
1794            fb.widget(&a);
1795            fb.build();
1796        }
1797
1798        #[test]
1799        fn test_insert_remove() {
1800            let a = FocusFlag::named("a");
1801            let b = FocusFlag::named("b");
1802            let c = FocusFlag::named("c");
1803            let d = FocusFlag::named("d");
1804            let e = FocusFlag::named("e");
1805            let f = FocusFlag::named("f");
1806            let g = FocusFlag::named("g");
1807            let h = FocusFlag::named("h");
1808            let i = FocusFlag::named("i");
1809
1810            let mut fb = FocusBuilder::new(None);
1811            fb.widget(&a);
1812            fb.widget(&b);
1813            fb.widget(&c);
1814            let ff = fb.build();
1815            assert_eq!(ff.core.focus_flags[0], a);
1816            assert_eq!(ff.core.focus_flags[1], b);
1817            assert_eq!(ff.core.focus_flags[2], c);
1818
1819            let cc = FocusFlag::named("cc");
1820            let mut fb = FocusBuilder::new(None);
1821            fb.widget(&a);
1822            let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1823            fb.widget(&d);
1824            fb.widget(&e);
1825            fb.widget(&f);
1826            fb.end(cc_end);
1827            fb.widget(&b);
1828            fb.widget(&c);
1829            let mut ff = fb.build();
1830            assert_eq!(ff.core.focus_flags[0], a);
1831            assert_eq!(ff.core.focus_flags[1], d);
1832            assert_eq!(ff.core.focus_flags[2], e);
1833            assert_eq!(ff.core.focus_flags[3], f);
1834            assert_eq!(ff.core.focus_flags[4], b);
1835            assert_eq!(ff.core.focus_flags[5], c);
1836            assert_eq!(ff.core.containers[0].1, 1..4);
1837
1838            struct DD {
1839                dd: FocusFlag,
1840                g: FocusFlag,
1841                h: FocusFlag,
1842                i: FocusFlag,
1843            }
1844
1845            impl HasFocus for DD {
1846                fn build(&self, fb: &mut FocusBuilder) {
1847                    let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1848                    fb.widget(&self.g);
1849                    fb.widget(&self.h);
1850                    fb.widget(&self.i);
1851                    fb.end(tag);
1852                }
1853
1854                fn focus(&self) -> FocusFlag {
1855                    self.dd.clone()
1856                }
1857
1858                fn area(&self) -> Rect {
1859                    Rect::default()
1860                }
1861            }
1862
1863            let dd = DD {
1864                dd: FocusFlag::named("dd"),
1865                g: g.clone(),
1866                h: h.clone(),
1867                i: i.clone(),
1868            };
1869            ff.replace_container(&cc, &dd);
1870            assert_eq!(ff.core.focus_flags[0], a);
1871            assert_eq!(ff.core.focus_flags[1], g);
1872            assert_eq!(ff.core.focus_flags[2], h);
1873            assert_eq!(ff.core.focus_flags[3], i);
1874            assert_eq!(ff.core.focus_flags[4], b);
1875            assert_eq!(ff.core.focus_flags[5], c);
1876            assert_eq!(ff.core.containers[0].1, 1..4);
1877        }
1878    }
1879}
1880
1881impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1882    #[inline(always)]
1883    fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1884        match event {
1885            ct_event!(keycode press Tab) => {
1886                focus_debug!(
1887                    self.core,
1888                    "Tab {:?}",
1889                    self.focused().map(|v| v.name().to_string())
1890                );
1891                let r = if self.next() {
1892                    Outcome::Changed
1893                } else {
1894                    Outcome::Continue
1895                };
1896                focus_debug!(
1897                    self.core,
1898                    "    -> {:?}",
1899                    self.focused().map(|v| v.name().to_string())
1900                );
1901                r
1902            }
1903            ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1904                focus_debug!(
1905                    self.core,
1906                    "BackTab {:?}",
1907                    self.focused().map(|v| v.name().to_string())
1908                );
1909                let r = if self.prev() {
1910                    Outcome::Changed
1911                } else {
1912                    Outcome::Continue
1913                };
1914                focus_debug!(
1915                    self.core,
1916                    "    -> {:?}",
1917                    self.focused().map(|v| v.name().to_string())
1918                );
1919                r
1920            }
1921            _ => self.handle(event, MouseOnly),
1922        }
1923    }
1924}
1925
1926impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1927    #[inline(always)]
1928    fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1929        match event {
1930            ct_event!(mouse down Left for column, row) => {
1931                focus_debug!(self.core, "mouse down {},{}", column, row);
1932                if self.focus_at(*column, *row) {
1933                    focus_debug!(
1934                        self.core,
1935                        "    -> {:?}",
1936                        self.focused().map(|v| v.name().to_string())
1937                    );
1938                    Outcome::Changed
1939                } else {
1940                    self.reset_lost_gained();
1941                    Outcome::Continue
1942                }
1943            }
1944            _ => {
1945                self.reset_lost_gained();
1946                Outcome::Continue
1947            }
1948        }
1949    }
1950}
1951
1952/// Handle all events.
1953#[inline(always)]
1954pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1955    HandleEvent::handle(focus, event, Regular)
1956}