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