rat_focus/
focus.rs

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