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