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())
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                if !matches!(navigable, Navigation::Mouse | Navigation::None) {
955                    focus_debug!(self, "{:#?}", self);
956                    panic!(
957                        "Duplicate flag is only allowed if the second call uses Navigation::Mouse|Navigation::None. Was {:?}.",
958                        focus
959                    )
960                }
961            }
962
963            focus_debug!(self, "widget {:?}", focus);
964
965            self.focus_ids.insert(focus.widget_id());
966            self.focus_flags.push(focus);
967            self.duplicate.push(duplicate);
968            self.areas.push((area, self.z_base + area_z));
969            self.navigable.push(navigable);
970        }
971
972        /// Start a container widget.
973        ///
974        /// Returns the FocusFlag of the container. This flag must
975        /// be used to close the container with [end](Self::end).
976        ///
977        /// __Panic__
978        ///
979        /// Panics if the same container-flag is added twice.
980        #[must_use]
981        pub fn start_with_flags(
982            &mut self,
983            container_flag: FocusFlag,
984            area: Rect,
985            area_z: u16,
986        ) -> FocusFlag {
987            focus_debug!(self, "start container {:?}", container_flag);
988
989            // no duplicates allowed for containers.
990            assert!(!self.container_ids.contains(&container_flag.widget_id()));
991
992            self.z_base += area_z;
993
994            let len = self.focus_flags.len();
995            self.container_ids.insert(container_flag.widget_id());
996            self.containers.push((
997                Container {
998                    container_flag: container_flag.clone(),
999                    area: (area, self.z_base),
1000                    delta_z: area_z,
1001                    complete: false,
1002                },
1003                len..len,
1004            ));
1005
1006            container_flag
1007        }
1008
1009        /// Build the Focus.
1010        ///
1011        /// If the previous Focus is known, this will also
1012        /// reset the FocusFlag for any widget no longer part of
1013        /// the Focus.
1014        pub fn build(mut self) -> Focus {
1015            // cleanup outcasts.
1016            for v in &self.last.focus_flags {
1017                if !self.focus_ids.contains(&v.widget_id()) {
1018                    v.clear();
1019                }
1020            }
1021            for (v, _) in &self.last.containers {
1022                let have_container = self
1023                    .containers
1024                    .iter()
1025                    .any(|(c, _)| v.container_flag == c.container_flag);
1026                if !have_container {
1027                    v.container_flag.clear();
1028                }
1029            }
1030            self.last.clear();
1031
1032            // check new tree.
1033            for (c, _) in self.containers.iter_mut().rev() {
1034                if !c.complete {
1035                    panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
1036                }
1037            }
1038
1039            let log = self.last.log.get();
1040            let insta_panic = self.last.insta_panic.get();
1041
1042            Focus {
1043                last: self.last,
1044                core: FocusCore {
1045                    log: Cell::new(log),
1046                    insta_panic: Cell::new(insta_panic),
1047                    focus_ids: self.focus_ids,
1048                    focus_flags: self.focus_flags,
1049                    duplicate: self.duplicate,
1050                    areas: self.areas,
1051                    navigable: self.navigable,
1052                    container_ids: self.container_ids,
1053                    containers: self.containers,
1054                },
1055            }
1056        }
1057    }
1058
1059    /// Struct for the data of the focus-container itself.
1060    #[derive(Debug, Clone)]
1061    struct Container {
1062        /// Summarizes all the contained FocusFlags.
1063        /// If any of them has the focus set, this will be set too.
1064        /// This can help if you build compound widgets.
1065        container_flag: FocusFlag,
1066        /// Area for the whole compound.
1067        /// Contains the area and a z-value.
1068        area: (Rect, u16),
1069        /// Delta Z value compared to the enclosing container.
1070        delta_z: u16,
1071        /// Flag for construction.
1072        complete: bool,
1073    }
1074
1075    /// Focus core.
1076    #[derive(Debug, Default, Clone)]
1077    pub(super) struct FocusCore {
1078        /// Focus logging
1079        pub(super) log: Cell<bool>,
1080        pub(super) insta_panic: Cell<bool>,
1081
1082        /// List of focus-ids.
1083        focus_ids: HashSet<usize, FxBuildHasher>,
1084        /// List of flags.
1085        focus_flags: Vec<FocusFlag>,
1086        /// Is the flag the primary flag, or just a duplicate
1087        /// to allow for multiple areas.
1088        duplicate: Vec<bool>,
1089        /// Areas for each widget.
1090        /// Contains the area and a z-value for the area.
1091        areas: Vec<(Rect, u16)>,
1092        /// Keyboard navigable
1093        // TODO: use FocusFlag.navigation() too. this is the override.
1094        navigable: Vec<Navigation>,
1095        /// List of focus-ids.
1096        container_ids: HashSet<usize, FxBuildHasher>,
1097        /// List of containers and their dependencies.
1098        /// Range here is a range in the vecs above. The ranges are
1099        /// all disjoint or completely contained within one other.
1100        /// No criss-cross intersections.
1101        containers: Vec<(Container, Range<usize>)>,
1102    }
1103
1104    impl FocusCore {
1105        /// Clear.
1106        pub(super) fn clear(&mut self) {
1107            self.focus_ids.clear();
1108            self.focus_flags.clear();
1109            self.duplicate.clear();
1110            self.areas.clear();
1111            self.navigable.clear();
1112            self.container_ids.clear();
1113            self.containers.clear();
1114        }
1115
1116        /// Find the FocusFlag by widget_id
1117        pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
1118            self.focus_flags
1119                .iter()
1120                .find(|v| widget_id == v.widget_id())
1121                .cloned()
1122        }
1123
1124        /// Is a widget?
1125        pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
1126            self.focus_ids.contains(&focus_flag.widget_id())
1127        }
1128
1129        /// Find the first occurrence of the given focus-flag.
1130        pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
1131            self.focus_flags
1132                .iter()
1133                .enumerate()
1134                .find(|(_, f)| *f == focus_flag)
1135                .map(|(idx, _)| idx)
1136        }
1137
1138        /// Is a container
1139        pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
1140            self.container_ids.contains(&focus_flag.widget_id())
1141        }
1142
1143        /// Find the given container-flag in the list of sub-containers.
1144        pub(super) fn container_index_of(
1145            &self,
1146            container_flag: &FocusFlag,
1147        ) -> Option<(usize, Range<usize>)> {
1148            self.containers
1149                .iter()
1150                .enumerate()
1151                .find(|(_, (c, _))| &c.container_flag == container_flag)
1152                .map(|(idx, (_, range))| (idx, range.clone()))
1153        }
1154
1155        /// Append a container.
1156        ///
1157        /// * pos - position inside the focus-flags
1158        /// * cpos - position inside the sub-containers
1159        pub(super) fn insert_container(
1160            &mut self,
1161            idx: usize,
1162            cidx: usize,
1163            mut container: FocusCore,
1164        ) {
1165            for c in &self.focus_flags {
1166                for d in &container.focus_flags {
1167                    assert_ne!(c, d);
1168                }
1169            }
1170
1171            // range for the data of the added container.
1172            let start = idx;
1173            let end = idx + container.focus_flags.len();
1174
1175            self.focus_ids.extend(container.focus_ids.iter());
1176            self.focus_flags
1177                .splice(idx..idx, container.focus_flags.drain(..));
1178            self.duplicate
1179                .splice(idx..idx, container.duplicate.drain(..));
1180            self.areas.splice(idx..idx, container.areas.drain(..));
1181            self.navigable
1182                .splice(idx..idx, container.navigable.drain(..));
1183
1184            // expand current ranges
1185            for (_, r) in &mut self.containers {
1186                *r = Self::expand(start..end, r.clone());
1187            }
1188            // shift inserted ranges into place
1189            self.containers.splice(
1190                cidx..cidx,
1191                container
1192                    .containers
1193                    .drain(..)
1194                    .map(|(c, r)| (c, Self::shift(start, r))),
1195            );
1196            self.container_ids.extend(container.container_ids.iter());
1197        }
1198
1199        /// Remove everything for the given container.
1200        /// Return the extracted values as FocusCore.
1201        pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1202            let crange = self.containers[cidx].1.clone();
1203
1204            // remove
1205            let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1206            let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1207            for f in focus_flags.iter() {
1208                self.focus_ids.remove(&f.widget_id());
1209                focus_ids.insert(f.widget_id());
1210            }
1211            let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1212            let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1213            let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1214            let sub_containers = self
1215                .containers
1216                .iter()
1217                .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1218                .cloned()
1219                .collect::<Vec<_>>();
1220            // remove the container and all sub-containers in the range.
1221            self.containers
1222                .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1223            let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1224            for (sc, _) in sub_containers.iter() {
1225                self.container_ids.remove(&sc.container_flag.widget_id());
1226                sub_container_ids.insert(sc.container_flag.widget_id());
1227            }
1228
1229            // adjust the remaining sub-containers
1230            for (_, r) in &mut self.containers {
1231                *r = Self::shrink(crange.start..crange.end, r.clone());
1232            }
1233
1234            FocusCore {
1235                log: Cell::new(false),
1236                insta_panic: Cell::new(false),
1237                focus_ids,
1238                focus_flags,
1239                duplicate,
1240                areas,
1241                navigable,
1242                container_ids: sub_container_ids,
1243                containers: sub_containers,
1244            }
1245        }
1246
1247        // shift the ranges left by n
1248        fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1249            range.start + n..range.end + n
1250        }
1251
1252        // expand the range caused by insert
1253        fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1254            let len = insert.end - insert.start;
1255
1256            if range.start >= insert.start {
1257                range.start += len;
1258            }
1259            if range.end > insert.start {
1260                range.end += len;
1261            }
1262            range
1263        }
1264
1265        // shrink the range caused by remove
1266        fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1267            let len = remove.end - remove.start;
1268
1269            if range.start < remove.start {
1270                // leave
1271            } else if range.start >= remove.start && range.start <= remove.end {
1272                range.start = remove.start;
1273            } else {
1274                range.start -= len;
1275            }
1276
1277            if range.end < remove.start {
1278                // leave
1279            } else if range.end >= remove.start && range.end <= remove.end {
1280                range.end = remove.start;
1281            } else {
1282                range.end -= len;
1283            }
1284
1285            range
1286        }
1287
1288        /// Reset the flags for a new round.
1289        /// set_lost - copy the current focus to the lost flag.
1290        fn __start_change(&self, set_lost: bool) {
1291            for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1292                if *duplicate {
1293                    // skip duplicates
1294                    continue;
1295                }
1296                if set_lost {
1297                    f.set_lost(f.get());
1298                } else {
1299                    f.set_lost(false);
1300                }
1301                f.set_gained(false);
1302                f.set(false);
1303            }
1304        }
1305
1306        /// Set the focus to this index. Doesn't touch
1307        /// other flags.
1308        fn __focus(&self, n: usize, set_lost: bool) -> bool {
1309            if let Some(f) = self.focus_flags.get(n) {
1310                focus_debug!(self, "    -> focus {}:{:?}", n, f.name());
1311                f.set(true);
1312                if set_lost {
1313                    if f.lost() {
1314                        // new focus same as old.
1315                        // reset lost + gained
1316                        f.set_lost(false);
1317                        f.set_gained(false);
1318                        false
1319                    } else {
1320                        f.set_gained(true);
1321                        true
1322                    }
1323                } else {
1324                    false
1325                }
1326            } else {
1327                false
1328            }
1329        }
1330
1331        /// Accumulate all container flags.
1332        #[allow(clippy::collapsible_if)]
1333        fn __accumulate(&self) {
1334            for (n, f) in self.focus_flags.iter().enumerate() {
1335                if f.gained() && !self.duplicate[n] {
1336                    if let Some(on_gained_cb) = f.0.on_gained.borrow().as_ref() {
1337                        focus_debug!(self, "    -> notify_on_gained {}:{:?}", n, f.name());
1338                        on_gained_cb();
1339                    }
1340                }
1341                if f.lost() && !self.duplicate[n] {
1342                    if let Some(on_lost_cb) = f.0.on_lost.borrow().as_ref() {
1343                        focus_debug!(self, "    -> notify_on_lost {}:{:?}", n, f.name());
1344                        on_lost_cb();
1345                    }
1346                }
1347            }
1348
1349            for (f, r) in &self.containers {
1350                let mut any_gained = false;
1351                let mut any_lost = false;
1352                let mut any_focused = false;
1353
1354                for idx in r.clone() {
1355                    any_gained |= self.focus_flags[idx].gained();
1356                    any_lost |= self.focus_flags[idx].lost();
1357                    any_focused |= self.focus_flags[idx].get();
1358                }
1359
1360                f.container_flag.set(any_focused);
1361                f.container_flag.set_lost(any_lost && !any_gained);
1362                if any_lost && !any_gained {
1363                    if let Some(on_lost_cb) = f.container_flag.0.on_lost.borrow().as_ref() {
1364                        focus_debug!(
1365                            self,
1366                            "-> notify_on_lost container {:?}",
1367                            f.container_flag.name()
1368                        );
1369                        on_lost_cb();
1370                    }
1371                }
1372                f.container_flag.set_gained(any_gained && !any_lost);
1373                if any_gained && !any_lost {
1374                    if let Some(on_gained_cb) = f.container_flag.0.on_gained.borrow().as_ref() {
1375                        focus_debug!(
1376                            self,
1377                            "-> notify_on_gained container {:?}",
1378                            f.container_flag.name()
1379                        );
1380                        on_gained_cb();
1381                    }
1382                }
1383            }
1384        }
1385
1386        /// Reset all lost+gained+focus flags.
1387        pub(super) fn reset(&self) {
1388            for f in self.focus_flags.iter() {
1389                f.set(false);
1390                f.set_lost(false);
1391                f.set_gained(false);
1392            }
1393            for (f, _) in self.containers.iter() {
1394                f.container_flag.set(false);
1395                f.container_flag.set_gained(false);
1396                f.container_flag.set_lost(false);
1397            }
1398        }
1399
1400        /// Reset all lost+gained flags.
1401        pub(super) fn reset_lost_gained(&self) {
1402            for f in self.focus_flags.iter() {
1403                f.set_lost(false);
1404                f.set_gained(false);
1405            }
1406            for (f, _) in self.containers.iter() {
1407                f.container_flag.set_gained(false);
1408                f.container_flag.set_lost(false);
1409            }
1410        }
1411
1412        /// Set the initial focus.
1413        pub(super) fn first(&self) {
1414            if let Some(n) = self.first_navigable(0) {
1415                self.__start_change(true);
1416                self.__focus(n, true);
1417                self.__accumulate();
1418            } else {
1419                focus_debug!(self, "    -> no navigable widget");
1420            }
1421        }
1422
1423        /// Clear the focus.
1424        pub(super) fn none(&self) {
1425            self.__start_change(true);
1426            self.__accumulate();
1427        }
1428
1429        /// Set the initial focus.
1430        pub(super) fn first_container(&self, container: &FocusFlag) {
1431            if let Some((_idx, range)) = self.container_index_of(container) {
1432                if let Some(n) = self.first_navigable(range.start) {
1433                    if n < range.end {
1434                        self.__start_change(true);
1435                        self.__focus(n, true);
1436                        self.__accumulate();
1437                    } else {
1438                        focus_debug!(self, "    -> no navigable widget for container");
1439                    }
1440                } else {
1441                    focus_debug!(self, "    -> no navigable widget");
1442                }
1443            } else {
1444                focus_fail!(self, "    => container not found");
1445            }
1446        }
1447
1448        /// Set the focus at the given index.
1449        pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1450            self.__start_change(set_lost);
1451            self.__focus(n, set_lost);
1452            self.__accumulate();
1453        }
1454
1455        /// Set the focus at the given screen position.
1456        /// Traverses the list to find the matching widget.
1457        /// Checks the area and the z-areas.
1458        pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1459            let pos = (col, row).into();
1460
1461            enum ZOrder {
1462                Widget(usize),
1463                Container(usize),
1464            }
1465
1466            // find any matching areas
1467            let mut z_order: Option<(ZOrder, u16)> = None;
1468            // search containers first. the widgets inside have the same z and are
1469            // more specific, so they should override.
1470            for (idx, (sub, _)) in self.containers.iter().enumerate() {
1471                if sub.area.0.contains(pos) {
1472                    focus_debug!(
1473                        self,
1474                        "    container area-match {:?}",
1475                        sub.container_flag.name()
1476                    );
1477
1478                    z_order = if let Some(zz) = z_order {
1479                        if zz.1 <= sub.area.1 {
1480                            Some((ZOrder::Container(idx), sub.area.1))
1481                        } else {
1482                            Some(zz)
1483                        }
1484                    } else {
1485                        Some((ZOrder::Container(idx), sub.area.1))
1486                    };
1487                }
1488            }
1489            // search widgets
1490            for (idx, area) in self.areas.iter().enumerate() {
1491                if area.0.contains(pos) {
1492                    focus_debug!(self, "    area-match {:?}", self.focus_flags[idx].name());
1493
1494                    z_order = if let Some(zz) = z_order {
1495                        if zz.1 <= area.1 {
1496                            Some((ZOrder::Widget(idx), area.1))
1497                        } else {
1498                            Some(zz)
1499                        }
1500                    } else {
1501                        Some((ZOrder::Widget(idx), area.1))
1502                    };
1503                }
1504            }
1505
1506            // process in order, last is on top if more than one.
1507            if let Some((idx, _)) = z_order {
1508                match idx {
1509                    ZOrder::Widget(idx) => {
1510                        if self.navigable[idx] != Navigation::None {
1511                            self.__start_change(true);
1512                            let r = self.__focus(idx, true);
1513                            self.__accumulate();
1514                            return r;
1515                        } else {
1516                            focus_debug!(
1517                                self,
1518                                "    -> not mouse reachable {:?}",
1519                                self.focus_flags[idx].name()
1520                            );
1521                            return false;
1522                        }
1523                    }
1524                    ZOrder::Container(idx) => {
1525                        let range = &self.containers[idx].1;
1526                        if let Some(n) = self.first_navigable(range.start) {
1527                            self.__start_change(true);
1528                            let r = self.__focus(n, true);
1529                            self.__accumulate();
1530                            return r;
1531                        }
1532                    }
1533                }
1534            }
1535
1536            // last is on top
1537            focus_debug!(self, "    -> no widget at pos");
1538
1539            false
1540        }
1541
1542        /// Expel focus from the given container.
1543        pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1544            if let Some((_idx, range)) = self.container_index_of(&flag) {
1545                self.__start_change(true);
1546                let n = self.next_navigable(range.end);
1547                self.__focus(n, true);
1548                self.__accumulate();
1549
1550                // still focused?
1551                if flag.is_focused() {
1552                    focus_debug!(self, "    -> focus not usable. cleared");
1553                    self.none();
1554                } else {
1555                    focus_debug!(self, "    -> expelled.");
1556                }
1557                true
1558            } else {
1559                focus_fail!(self, "    => container not found");
1560                false
1561            }
1562        }
1563
1564        /// Focus next.
1565        pub(super) fn next(&self) -> bool {
1566            self.__start_change(true);
1567            for (n, p) in self.focus_flags.iter().enumerate() {
1568                if p.lost() {
1569                    let n = self.next_navigable(n);
1570                    self.__focus(n, true);
1571                    self.__accumulate();
1572                    return true;
1573                }
1574            }
1575            if let Some(n) = self.first_navigable(0) {
1576                focus_debug!(
1577                    self,
1578                    "    use first_navigable {}:{:?}",
1579                    n,
1580                    self.focus_flags[n].name()
1581                );
1582                self.__focus(n, true);
1583                self.__accumulate();
1584                return true;
1585            }
1586            focus_debug!(self, "    -> no next");
1587            false
1588        }
1589
1590        /// Focus prev.
1591        pub(super) fn prev(&self) -> bool {
1592            self.__start_change(true);
1593            for (i, p) in self.focus_flags.iter().enumerate() {
1594                if p.lost() {
1595                    let n = self.prev_navigable(i);
1596                    self.__focus(n, true);
1597                    self.__accumulate();
1598                    return true;
1599                }
1600            }
1601            if let Some(n) = self.first_navigable(0) {
1602                focus_debug!(
1603                    self,
1604                    "    use first_navigable {}:{:?}",
1605                    n,
1606                    self.focus_flags[n].name()
1607                );
1608                self.__focus(n, true);
1609                self.__accumulate();
1610                return true;
1611            }
1612            focus_debug!(self, "    -> no prev");
1613            false
1614        }
1615
1616        /// Returns the navigation flag for the focused widget.
1617        pub(super) fn navigation(&self) -> Option<Navigation> {
1618            self.focus_flags
1619                .iter()
1620                .enumerate()
1621                .find(|(_, v)| v.get())
1622                .map(|(i, _)| self.navigable[i])
1623        }
1624
1625        /// Currently focused.
1626        pub(super) fn focused(&self) -> Option<FocusFlag> {
1627            self.focus_flags.iter().find(|v| v.get()).cloned()
1628        }
1629
1630        /// Last lost focus.
1631        pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1632            self.focus_flags.iter().find(|v| v.lost()).cloned()
1633        }
1634
1635        /// Current gained focus.
1636        pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1637            self.focus_flags.iter().find(|v| v.gained()).cloned()
1638        }
1639
1640        /// First navigable flag starting at n.
1641        fn first_navigable(&self, start: usize) -> Option<usize> {
1642            focus_debug!(
1643                self,
1644                "first navigable, start at {}:{:?} ",
1645                start,
1646                if start < self.focus_flags.len() {
1647                    self.focus_flags[start].name()
1648                } else {
1649                    "beginning".into()
1650                }
1651            );
1652            for n in start..self.focus_flags.len() {
1653                if matches!(
1654                    self.navigable[n],
1655                    Navigation::Reach
1656                        | Navigation::ReachLeaveBack
1657                        | Navigation::ReachLeaveFront
1658                        | Navigation::Regular
1659                ) {
1660                    focus_debug!(self, "    -> {}:{:?}", n, self.focus_flags[n].name());
1661                    return Some(n);
1662                }
1663            }
1664            focus_debug!(self, "    -> no first");
1665            None
1666        }
1667
1668        /// Next navigable flag, starting at start.
1669        fn next_navigable(&self, start: usize) -> usize {
1670            focus_debug!(
1671                self,
1672                "next navigable after {}:{:?}",
1673                start,
1674                if start < self.focus_flags.len() {
1675                    self.focus_flags[start].name()
1676                } else {
1677                    "last".into()
1678                }
1679            );
1680
1681            let mut n = start;
1682            loop {
1683                n = if n + 1 < self.focus_flags.len() {
1684                    n + 1
1685                } else {
1686                    0
1687                };
1688                if matches!(
1689                    self.navigable[n],
1690                    Navigation::Reach
1691                        | Navigation::ReachLeaveBack
1692                        | Navigation::ReachLeaveFront
1693                        | Navigation::Regular
1694                ) {
1695                    focus_debug!(self, "    -> {}:{:?}", n, self.focus_flags[n].name());
1696                    return n;
1697                }
1698                if n == start {
1699                    focus_debug!(self, "    -> {}:end at start", n);
1700                    return n;
1701                }
1702            }
1703        }
1704
1705        /// Previous navigable flag, starting at start.
1706        fn prev_navigable(&self, start: usize) -> usize {
1707            focus_debug!(
1708                self,
1709                "prev navigable before {}:{:?}",
1710                start,
1711                self.focus_flags[start].name()
1712            );
1713
1714            let mut n = start;
1715            loop {
1716                n = if n > 0 {
1717                    n - 1
1718                } else {
1719                    self.focus_flags.len() - 1
1720                };
1721                if matches!(
1722                    self.navigable[n],
1723                    Navigation::Reach
1724                        | Navigation::ReachLeaveBack
1725                        | Navigation::ReachLeaveFront
1726                        | Navigation::Regular
1727                ) {
1728                    focus_debug!(self, "    -> {}:{:?}", n, self.focus_flags[n].name());
1729                    return n;
1730                }
1731                if n == start {
1732                    focus_debug!(self, "    -> {}:end at start", n);
1733                    return n;
1734                }
1735            }
1736        }
1737
1738        /// Debug destructuring.
1739        #[allow(clippy::type_complexity)]
1740        pub(super) fn clone_destruct(
1741            &self,
1742        ) -> (
1743            Vec<FocusFlag>,
1744            Vec<bool>,
1745            Vec<(Rect, u16)>,
1746            Vec<Navigation>,
1747            Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1748        ) {
1749            (
1750                self.focus_flags.clone(),
1751                self.duplicate.clone(),
1752                self.areas.clone(),
1753                self.navigable.clone(),
1754                self.containers
1755                    .iter()
1756                    .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1757                    .collect::<Vec<_>>(),
1758            )
1759        }
1760    }
1761
1762    #[cfg(test)]
1763    mod test {
1764        use crate::focus::core::FocusCore;
1765        use crate::{FocusBuilder, FocusFlag, HasFocus};
1766        use ratatui::layout::Rect;
1767
1768        #[test]
1769        fn test_change() {
1770            assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1771            assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1772
1773            assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1774            assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1775            assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1776            assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1777            assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1778
1779            assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1780            assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1781            assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1782            assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1783            assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1784
1785            assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1786            assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1787            assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1788            assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1789            assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1790
1791            assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1792            assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1793            assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1794            assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1795            assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1796        }
1797
1798        #[test]
1799        #[should_panic]
1800        fn test_double_insert() {
1801            let a = FocusFlag::named("a");
1802            let b = FocusFlag::named("b");
1803
1804            let mut fb = FocusBuilder::new(None);
1805            fb.widget(&a);
1806            fb.widget(&b);
1807            fb.widget(&a);
1808            fb.build();
1809        }
1810
1811        #[test]
1812        fn test_insert_remove() {
1813            let a = FocusFlag::named("a");
1814            let b = FocusFlag::named("b");
1815            let c = FocusFlag::named("c");
1816            let d = FocusFlag::named("d");
1817            let e = FocusFlag::named("e");
1818            let f = FocusFlag::named("f");
1819            let g = FocusFlag::named("g");
1820            let h = FocusFlag::named("h");
1821            let i = FocusFlag::named("i");
1822
1823            let mut fb = FocusBuilder::new(None);
1824            fb.widget(&a);
1825            fb.widget(&b);
1826            fb.widget(&c);
1827            let ff = fb.build();
1828            assert_eq!(ff.core.focus_flags[0], a);
1829            assert_eq!(ff.core.focus_flags[1], b);
1830            assert_eq!(ff.core.focus_flags[2], c);
1831
1832            let cc = FocusFlag::named("cc");
1833            let mut fb = FocusBuilder::new(None);
1834            fb.widget(&a);
1835            let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1836            fb.widget(&d);
1837            fb.widget(&e);
1838            fb.widget(&f);
1839            fb.end(cc_end);
1840            fb.widget(&b);
1841            fb.widget(&c);
1842            let mut ff = fb.build();
1843            assert_eq!(ff.core.focus_flags[0], a);
1844            assert_eq!(ff.core.focus_flags[1], d);
1845            assert_eq!(ff.core.focus_flags[2], e);
1846            assert_eq!(ff.core.focus_flags[3], f);
1847            assert_eq!(ff.core.focus_flags[4], b);
1848            assert_eq!(ff.core.focus_flags[5], c);
1849            assert_eq!(ff.core.containers[0].1, 1..4);
1850
1851            struct DD {
1852                dd: FocusFlag,
1853                g: FocusFlag,
1854                h: FocusFlag,
1855                i: FocusFlag,
1856            }
1857
1858            impl HasFocus for DD {
1859                fn build(&self, fb: &mut FocusBuilder) {
1860                    let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1861                    fb.widget(&self.g);
1862                    fb.widget(&self.h);
1863                    fb.widget(&self.i);
1864                    fb.end(tag);
1865                }
1866
1867                fn focus(&self) -> FocusFlag {
1868                    self.dd.clone()
1869                }
1870
1871                fn area(&self) -> Rect {
1872                    Rect::default()
1873                }
1874            }
1875
1876            let dd = DD {
1877                dd: FocusFlag::named("dd"),
1878                g: g.clone(),
1879                h: h.clone(),
1880                i: i.clone(),
1881            };
1882            ff.replace_container(&cc, &dd);
1883            assert_eq!(ff.core.focus_flags[0], a);
1884            assert_eq!(ff.core.focus_flags[1], g);
1885            assert_eq!(ff.core.focus_flags[2], h);
1886            assert_eq!(ff.core.focus_flags[3], i);
1887            assert_eq!(ff.core.focus_flags[4], b);
1888            assert_eq!(ff.core.focus_flags[5], c);
1889            assert_eq!(ff.core.containers[0].1, 1..4);
1890        }
1891    }
1892}
1893
1894impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1895    #[inline(always)]
1896    fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1897        match event {
1898            ct_event!(keycode press Tab) => {
1899                focus_debug!(
1900                    self.core,
1901                    "Tab {:?}",
1902                    self.focused().map(|v| v.name().to_string())
1903                );
1904                let r = if self.next() {
1905                    Outcome::Changed
1906                } else {
1907                    Outcome::Continue
1908                };
1909                focus_debug!(
1910                    self.core,
1911                    "    -> {:?} {:?}",
1912                    r,
1913                    self.focused().map(|v| v.name().to_string())
1914                );
1915                r
1916            }
1917            ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1918                focus_debug!(
1919                    self.core,
1920                    "BackTab {:?}",
1921                    self.focused().map(|v| v.name().to_string())
1922                );
1923                let r = if self.prev() {
1924                    Outcome::Changed
1925                } else {
1926                    Outcome::Continue
1927                };
1928                focus_debug!(
1929                    self.core,
1930                    "    -> {:?} {:?}",
1931                    r,
1932                    self.focused().map(|v| v.name().to_string())
1933                );
1934                r
1935            }
1936            _ => self.handle(event, MouseOnly),
1937        }
1938    }
1939}
1940
1941impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1942    #[inline(always)]
1943    fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1944        match event {
1945            ct_event!(mouse down Left for column, row) => {
1946                focus_debug!(self.core, "mouse down {},{}", column, row);
1947                if self.focus_at(*column, *row) {
1948                    focus_debug!(
1949                        self.core,
1950                        "    -> {:?}",
1951                        self.focused().map(|v| v.name().to_string())
1952                    );
1953                    Outcome::Changed
1954                } else {
1955                    self.reset_lost_gained();
1956                    Outcome::Continue
1957                }
1958            }
1959            _ => {
1960                self.reset_lost_gained();
1961                Outcome::Continue
1962            }
1963        }
1964    }
1965}
1966
1967/// Handle all events.
1968#[inline(always)]
1969pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1970    HandleEvent::handle(focus, event, Regular)
1971}