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