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