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        pub fn widget_navigate(
648            &mut self,
649            widget: &dyn HasFocus,
650            navigation: Navigation,
651        ) -> &mut Self {
652            widget.build(self);
653
654            // override navigation for the widget
655            if let Some(idx) = self.focus_flags.iter().position(|v| *v == widget.focus()) {
656                focus_debug!(
657                    self.log,
658                    "override navigation for {:?} with {:?}",
659                    widget.focus(),
660                    navigation
661                );
662
663                self.navigable[idx] = navigation;
664            } else {
665                if self.container_ids.contains(&widget.focus().widget_id()) {
666                    focus_debug!(
667                        self.log,
668                        "FAIL to override navigation for {:?}. This is a container.",
669                        widget.focus(),
670                    );
671                } else {
672                    focus_debug!(
673                        self.log,
674                        "FAIL to override navigation for {:?}. Widget doesn't use this focus-flag",
675                        widget.focus(),
676                    );
677                }
678            }
679
680            self
681        }
682
683        /// Add a bunch of widget.
684        ///
685        /// The widget is added to all open containers.
686        #[inline]
687        pub fn widgets<const N: usize>(&mut self, widgets: [&dyn HasFocus; N]) -> &mut Self {
688            for widget in widgets {
689                widget.build(self);
690            }
691            self
692        }
693
694        /// Start a container widget. Must be matched with
695        /// the equivalent [end](Self::end). Uses focus(), area() and
696        /// z_area() of the given container. navigable() is
697        /// currently not used, just leave it at the default.
698        ///
699        /// __Attention__
700        ///
701        /// Use the returned value when calling [end](Self::end).
702        ///
703        /// __Panic__
704        ///
705        /// Panics if the same container-flag is added twice.
706        #[must_use]
707        pub fn start(&mut self, container: &dyn HasFocus) -> FocusFlag {
708            self.start_with_flags(container.focus(), container.area(), container.area_z())
709        }
710
711        /// End a container widget.
712        pub fn end(&mut self, tag: FocusFlag) {
713            focus_debug!(self.log, "end container {:?}", tag);
714            assert!(self.container_ids.contains(&tag.widget_id()));
715
716            for (c, r) in self.containers.iter_mut().rev() {
717                if c.container_flag != tag {
718                    if !c.complete {
719                        panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
720                    }
721                } else {
722                    r.end = self.focus_flags.len();
723                    c.complete = true;
724
725                    focus_debug!(self.log, "container range {:?}", r);
726
727                    self.z_base -= c.delta_z;
728
729                    break;
730                }
731            }
732        }
733
734        /// Directly add the given widget's flags. Doesn't call
735        /// build() instead it uses focus(), etc. and appends a single widget.
736        pub fn leaf_widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
737            self.widget_with_flags(
738                widget.focus(),
739                widget.area(),
740                widget.area_z(),
741                widget.navigable(),
742            );
743            self
744        }
745
746        /// Manually add a widgets flags.
747        ///
748        /// This is intended to be used when __implementing__
749        /// HasFocus::build() for a widget.
750        ///
751        /// In all other situations it's better to use [widget()](FocusBuilder::widget).
752        ///
753        /// __Panic__
754        ///
755        /// Panics if the same focus-flag is added twice.
756        /// Except it is allowable to add the flag a second time with
757        /// Navigation::Mouse or Navigation::None
758        pub fn widget_with_flags(
759            &mut self,
760            focus: FocusFlag,
761            area: Rect,
762            area_z: u16,
763            navigable: Navigation,
764        ) {
765            let duplicate = self.focus_ids.contains(&focus.widget_id());
766
767            // there can be a second entry for the same focus-flag
768            // if it is only for mouse interactions.
769            if duplicate {
770                assert!(matches!(navigable, Navigation::Mouse | Navigation::None))
771            }
772
773            focus_debug!(self.log, "widget {:?}", focus);
774
775            self.focus_ids.insert(focus.widget_id());
776            self.focus_flags.push(focus);
777            self.duplicate.push(duplicate);
778            self.areas.push((area, self.z_base + area_z));
779            self.navigable.push(navigable);
780        }
781
782        /// Start a container widget. Must be matched with
783        /// the equivalent [end](Self::end).
784        ///
785        /// __Attention__
786        ///
787        /// If container_flag is None a dummy flag will be created and
788        /// returned. Use the returned value when calling [end](Self::end).
789        ///
790        /// __Panic__
791        ///
792        /// Panics if the same container-flag is added twice.
793        #[must_use]
794        pub fn start_with_flags(
795            &mut self,
796            container_flag: FocusFlag,
797            area: Rect,
798            area_z: u16,
799        ) -> FocusFlag {
800            focus_debug!(self.log, "start container {:?}", container_flag);
801
802            // no duplicates allowed for containers.
803            assert!(!self.container_ids.contains(&container_flag.widget_id()));
804
805            self.z_base += area_z;
806
807            let len = self.focus_flags.len();
808            self.container_ids.insert(container_flag.widget_id());
809            self.containers.push((
810                Container {
811                    container_flag: container_flag.clone(),
812                    area: (area, self.z_base),
813                    delta_z: area_z,
814                    complete: false,
815                },
816                len..len,
817            ));
818
819            container_flag
820        }
821
822        /// Build the final Focus.
823        ///
824        /// If the old Focus has been set with new(), all widgets
825        /// that are no longer part of the focus will be cleared().
826        pub fn build(mut self) -> Focus {
827            // cleanup outcasts.
828            for v in &self.last.focus_flags {
829                if !self.focus_ids.contains(&v.widget_id()) {
830                    v.clear();
831                }
832            }
833            for (v, _) in &self.last.containers {
834                let have_container = self
835                    .containers
836                    .iter()
837                    .any(|(c, _)| v.container_flag == c.container_flag);
838                if !have_container {
839                    v.container_flag.clear();
840                }
841            }
842            self.last.clear();
843
844            // check new tree.
845            for (c, _) in self.containers.iter_mut().rev() {
846                if !c.complete {
847                    panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
848                }
849            }
850
851            let log = self.last.log.get();
852
853            Focus {
854                last: self.last,
855                core: FocusCore {
856                    log: Cell::new(log),
857                    focus_ids: self.focus_ids,
858                    focus_flags: self.focus_flags,
859                    duplicate: self.duplicate,
860                    areas: self.areas,
861                    navigable: self.navigable,
862                    container_ids: self.container_ids,
863                    containers: self.containers,
864                },
865            }
866        }
867    }
868
869    /// Struct for the data of the focus-container itself.
870    #[derive(Debug, Clone)]
871    struct Container {
872        /// Summarizes all the contained FocusFlags.
873        /// If any of them has the focus set, this will be set too.
874        /// This can help if you build compound widgets.
875        container_flag: FocusFlag,
876        /// Area for the whole compound.
877        /// Contains the area and a z-value.
878        area: (Rect, u16),
879        /// Delta Z value compared to the enclosing container.
880        delta_z: u16,
881        /// Flag for construction.
882        complete: bool,
883    }
884
885    /// Focus core.
886    #[derive(Debug, Default, Clone)]
887    pub(super) struct FocusCore {
888        /// Focus logging
889        pub(super) log: Cell<bool>,
890
891        /// List of focus-ids.
892        focus_ids: HashSet<usize, FxBuildHasher>,
893        /// List of flags.
894        focus_flags: Vec<FocusFlag>,
895        /// Is the flag the primary flag, or just a duplicate
896        /// to allow for multiple areas.
897        duplicate: Vec<bool>,
898        /// Areas for each widget.
899        /// Contains the area and a z-value for the area.
900        areas: Vec<(Rect, u16)>,
901        /// Keyboard navigable
902        navigable: Vec<Navigation>,
903        /// List of focus-ids.
904        container_ids: HashSet<usize, FxBuildHasher>,
905        /// List of containers and their dependencies.
906        /// Range here is a range in the vecs above. The ranges are
907        /// all disjoint or completely contained within one other.
908        /// No criss-cross intersections.
909        containers: Vec<(Container, Range<usize>)>,
910    }
911
912    impl FocusCore {
913        /// Clear.
914        pub(super) fn clear(&mut self) {
915            self.focus_ids.clear();
916            self.focus_flags.clear();
917            self.duplicate.clear();
918            self.areas.clear();
919            self.navigable.clear();
920            self.container_ids.clear();
921            self.containers.clear();
922        }
923
924        /// Is a widget?
925        pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
926            self.focus_ids.contains(&focus_flag.widget_id())
927        }
928
929        /// Find the first occurrence of the given focus-flag.
930        pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
931            self.focus_flags
932                .iter()
933                .enumerate()
934                .find(|(_, f)| *f == focus_flag)
935                .map(|(idx, _)| idx)
936        }
937
938        /// Is a container
939        pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
940            self.container_ids.contains(&focus_flag.widget_id())
941        }
942
943        /// Find the given container-flag in the list of sub-containers.
944        pub(super) fn container_index_of(
945            &self,
946            container_flag: &FocusFlag,
947        ) -> Option<(usize, Range<usize>)> {
948            self.containers
949                .iter()
950                .enumerate()
951                .find(|(_, (c, _))| &c.container_flag == container_flag)
952                .map(|(idx, (_, range))| (idx, range.clone()))
953        }
954
955        /// Append a container.
956        ///
957        /// * pos - position inside the focus-flags
958        /// * cpos - position inside the sub-containers
959        pub(super) fn insert_container(
960            &mut self,
961            idx: usize,
962            cidx: usize,
963            mut container: FocusCore,
964        ) {
965            for c in &self.focus_flags {
966                for d in &container.focus_flags {
967                    assert_ne!(c, d);
968                }
969            }
970
971            // range for the data of the added container.
972            let start = idx;
973            let end = idx + container.focus_flags.len();
974
975            self.focus_ids.extend(container.focus_ids.iter());
976            self.focus_flags
977                .splice(idx..idx, container.focus_flags.drain(..));
978            self.duplicate
979                .splice(idx..idx, container.duplicate.drain(..));
980            self.areas.splice(idx..idx, container.areas.drain(..));
981            self.navigable
982                .splice(idx..idx, container.navigable.drain(..));
983
984            // expand current ranges
985            for (_, r) in &mut self.containers {
986                *r = Self::expand(start..end, r.clone());
987            }
988            // shift inserted ranges into place
989            self.containers.splice(
990                cidx..cidx,
991                container
992                    .containers
993                    .drain(..)
994                    .map(|(c, r)| (c, Self::shift(start, r))),
995            );
996            self.container_ids.extend(container.container_ids.iter());
997        }
998
999        /// Remove everything for the given container.
1000        /// Return the extracted values as FocusCore.
1001        pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1002            let crange = self.containers[cidx].1.clone();
1003
1004            // remove
1005            let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1006            let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1007            for f in focus_flags.iter() {
1008                self.focus_ids.remove(&f.widget_id());
1009                focus_ids.insert(f.widget_id());
1010            }
1011            let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1012            let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1013            let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1014            let sub_containers = self
1015                .containers
1016                .iter()
1017                .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1018                .cloned()
1019                .collect::<Vec<_>>();
1020            // remove the container and all sub-containers in the range.
1021            self.containers
1022                .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1023            let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1024            for (sc, _) in sub_containers.iter() {
1025                self.container_ids.remove(&sc.container_flag.widget_id());
1026                sub_container_ids.insert(sc.container_flag.widget_id());
1027            }
1028
1029            // adjust the remaining sub-containers
1030            for (_, r) in &mut self.containers {
1031                *r = Self::shrink(crange.start..crange.end, r.clone());
1032            }
1033
1034            FocusCore {
1035                log: Cell::new(false),
1036                focus_ids,
1037                focus_flags,
1038                duplicate,
1039                areas,
1040                navigable,
1041                container_ids: sub_container_ids,
1042                containers: sub_containers,
1043            }
1044        }
1045
1046        // shift the ranges left by n
1047        fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1048            range.start + n..range.end + n
1049        }
1050
1051        // expand the range caused by insert
1052        fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1053            let len = insert.end - insert.start;
1054
1055            if range.start >= insert.start {
1056                range.start += len;
1057            }
1058            if range.end > insert.start {
1059                range.end += len;
1060            }
1061            range
1062        }
1063
1064        // shrink the range caused by remove
1065        fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1066            let len = remove.end - remove.start;
1067
1068            if range.start < remove.start {
1069                // leave
1070            } else if range.start >= remove.start && range.start <= remove.end {
1071                range.start = remove.start;
1072            } else {
1073                range.start -= len;
1074            }
1075
1076            if range.end < remove.start {
1077                // leave
1078            } else if range.end >= remove.start && range.end <= remove.end {
1079                range.end = remove.start;
1080            } else {
1081                range.end -= len;
1082            }
1083
1084            range
1085        }
1086
1087        /// Reset the flags for a new round.
1088        /// set_lost - copy the current focus to the lost flag.
1089        fn __start_change(&self, set_lost: bool) {
1090            for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1091                if *duplicate {
1092                    // skip duplicates
1093                    continue;
1094                }
1095                if set_lost {
1096                    f.set_lost(f.get());
1097                } else {
1098                    f.set_lost(false);
1099                }
1100                f.set_gained(false);
1101                f.set(false);
1102            }
1103        }
1104
1105        /// Set the focus to this index. Doesn't touch
1106        /// other flags.
1107        fn __focus(&self, n: usize, set_lost: bool) -> bool {
1108            if let Some(f) = self.focus_flags.get(n) {
1109                focus_debug!(self.log, "    -> manual focus {:?}", f.name());
1110                f.set(true);
1111                if set_lost {
1112                    if f.lost() {
1113                        // new focus same as old.
1114                        // reset lost + gained
1115                        f.set_lost(false);
1116                        f.set_gained(false);
1117                        false
1118                    } else {
1119                        f.set_gained(true);
1120                        true
1121                    }
1122                } else {
1123                    false
1124                }
1125            } else {
1126                false
1127            }
1128        }
1129
1130        /// Accumulate all container flags.
1131        fn __accumulate(&self) {
1132            for (f, r) in &self.containers {
1133                let mut any_gained = false;
1134                let mut any_lost = false;
1135                let mut any_focused = false;
1136
1137                for idx in r.clone() {
1138                    any_gained |= self.focus_flags[idx].gained();
1139                    any_lost |= self.focus_flags[idx].lost();
1140                    any_focused |= self.focus_flags[idx].get();
1141                }
1142
1143                f.container_flag.set(any_focused);
1144                f.container_flag.set_lost(any_lost && !any_gained);
1145                f.container_flag.set_gained(any_gained && !any_lost);
1146            }
1147        }
1148
1149        /// Reset all lost+gained+focus flags.
1150        pub(super) fn reset(&self) {
1151            for f in self.focus_flags.iter() {
1152                f.set(false);
1153                f.set_lost(false);
1154                f.set_gained(false);
1155            }
1156            for (f, _) in self.containers.iter() {
1157                f.container_flag.set(false);
1158                f.container_flag.set_gained(false);
1159                f.container_flag.set_lost(false);
1160            }
1161        }
1162
1163        /// Reset all lost+gained flags.
1164        pub(super) fn reset_lost_gained(&self) {
1165            for f in self.focus_flags.iter() {
1166                f.set_lost(false);
1167                f.set_gained(false);
1168            }
1169            for (f, _) in self.containers.iter() {
1170                f.container_flag.set_gained(false);
1171                f.container_flag.set_lost(false);
1172            }
1173        }
1174
1175        /// Set the initial focus.
1176        pub(super) fn first(&self) {
1177            self.__start_change(true);
1178            if let Some(n) = self.first_navigable(0) {
1179                focus_debug!(self.log, "    -> focus {:?}", self.focus_flags[n].name());
1180                self.__focus(n, true);
1181            } else {
1182                focus_debug!(self.log, "    -> no navigable widget");
1183            }
1184            self.__accumulate();
1185        }
1186
1187        /// Clear the focus.
1188        pub(super) fn none(&self) {
1189            self.__start_change(true);
1190            self.__accumulate();
1191        }
1192
1193        /// Set the initial focus.
1194        pub(super) fn first_container(&self, container: &FocusFlag) {
1195            self.__start_change(true);
1196            if let Some((_idx, range)) = self.container_index_of(container) {
1197                if let Some(n) = self.first_navigable(range.start) {
1198                    if n < range.end {
1199                        focus_debug!(self.log, "    -> focus {:?}", self.focus_flags[n].name());
1200                        self.__focus(n, true);
1201                    }
1202                } else {
1203                    focus_debug!(self.log, "    -> no navigable widget");
1204                }
1205            } else {
1206                focus_debug!(self.log, "    => container not found");
1207            }
1208            self.__accumulate();
1209        }
1210
1211        /// Set the focus at the given index.
1212        pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1213            self.__start_change(set_lost);
1214            self.__focus(n, set_lost);
1215            self.__accumulate();
1216        }
1217
1218        /// Set the focus at the given screen position.
1219        /// Traverses the list to find the matching widget.
1220        /// Checks the area and the z-areas.
1221        pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1222            let pos = (col, row).into();
1223
1224            enum ZOrder {
1225                Widget(usize),
1226                Container(usize),
1227            }
1228
1229            // find any matching areas
1230            let mut z_order: Option<(ZOrder, u16)> = None;
1231            // search containers first. the widgets inside have the same z and are
1232            // more specific, so they should override.
1233            for (idx, (sub, _)) in self.containers.iter().enumerate() {
1234                if sub.area.0.contains(pos) {
1235                    focus_debug!(
1236                        self.log,
1237                        "    container area-match {:?}",
1238                        sub.container_flag.name()
1239                    );
1240
1241                    z_order = if let Some(zz) = z_order {
1242                        if zz.1 <= sub.area.1 {
1243                            Some((ZOrder::Container(idx), sub.area.1))
1244                        } else {
1245                            Some(zz)
1246                        }
1247                    } else {
1248                        Some((ZOrder::Container(idx), sub.area.1))
1249                    };
1250                }
1251            }
1252            // search widgets
1253            for (idx, area) in self.areas.iter().enumerate() {
1254                if area.0.contains(pos) {
1255                    focus_debug!(
1256                        self.log,
1257                        "    area-match {:?}",
1258                        self.focus_flags[idx].name()
1259                    );
1260
1261                    z_order = if let Some(zz) = z_order {
1262                        if zz.1 <= area.1 {
1263                            Some((ZOrder::Widget(idx), area.1))
1264                        } else {
1265                            Some(zz)
1266                        }
1267                    } else {
1268                        Some((ZOrder::Widget(idx), area.1))
1269                    };
1270                }
1271            }
1272
1273            // process in order, last is on top if more than one.
1274            if let Some((idx, _)) = z_order {
1275                match idx {
1276                    ZOrder::Widget(idx) => {
1277                        if self.navigable[idx] != Navigation::None {
1278                            self.__start_change(true);
1279                            let r = self.__focus(idx, true);
1280                            self.__accumulate();
1281                            focus_debug!(
1282                                self.log,
1283                                "    -> focus {:?}",
1284                                self.focus_flags[idx].name()
1285                            );
1286                            return r;
1287                        } else {
1288                            focus_debug!(
1289                                self.log,
1290                                "    -> not mouse reachable {:?}",
1291                                self.focus_flags[idx].name()
1292                            );
1293                            return false;
1294                        }
1295                    }
1296                    ZOrder::Container(idx) => {
1297                        let range = &self.containers[idx].1;
1298                        if let Some(n) = self.first_navigable(range.start) {
1299                            self.__start_change(true);
1300                            let r = self.__focus(n, true);
1301                            self.__accumulate();
1302                            focus_debug!(self.log, "    -> focus {:?}", self.focus_flags[n].name());
1303                            return r;
1304                        }
1305                    }
1306                }
1307            }
1308
1309            // last is on top
1310            focus_debug!(self.log, "    -> no widget at pos");
1311
1312            false
1313        }
1314
1315        /// Expel focus from the given container.
1316        pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1317            if let Some((_idx, range)) = self.container_index_of(&flag) {
1318                self.__start_change(true);
1319                let n = self.next_navigable(range.end);
1320                self.__focus(n, true);
1321                self.__accumulate();
1322
1323                // still focused?
1324                if flag.is_focused() {
1325                    focus_debug!(self.log, "    -> focus not usable. cleared");
1326                    self.none();
1327                } else {
1328                    focus_debug!(self.log, "    -> expelled.");
1329                }
1330                true
1331            } else {
1332                focus_debug!(self.log, "    => container not found");
1333                false
1334            }
1335        }
1336
1337        /// Focus next.
1338        pub(super) fn next(&self) -> bool {
1339            self.__start_change(true);
1340            for (n, p) in self.focus_flags.iter().enumerate() {
1341                if p.lost() {
1342                    focus_debug!(self.log, "    current {:?}", p.name());
1343                    let n = self.next_navigable(n);
1344                    self.__focus(n, true);
1345                    self.__accumulate();
1346                    return true;
1347                }
1348            }
1349            if let Some(n) = self.first_navigable(0) {
1350                focus_debug!(self.log, "    -> focus {:?}", self.focus_flags[n].name());
1351                self.__focus(n, true);
1352                self.__accumulate();
1353                return true;
1354            }
1355            focus_debug!(self.log, "    -> no next");
1356            false
1357        }
1358
1359        /// Focus prev.
1360        pub(super) fn prev(&self) -> bool {
1361            self.__start_change(true);
1362            for (i, p) in self.focus_flags.iter().enumerate() {
1363                if p.lost() {
1364                    focus_debug!(self.log, "    current {:?}", p.name());
1365                    let n = self.prev_navigable(i);
1366                    self.__focus(n, true);
1367                    self.__accumulate();
1368                    return true;
1369                }
1370            }
1371            if let Some(n) = self.first_navigable(0) {
1372                focus_debug!(self.log, "    -> focus {:?}", self.focus_flags[n].name());
1373                self.__focus(n, true);
1374                self.__accumulate();
1375                return true;
1376            }
1377            focus_debug!(self.log, "    -> no prev");
1378            false
1379        }
1380
1381        /// Returns the navigation flag for the focused widget.
1382        pub(super) fn navigation(&self) -> Option<Navigation> {
1383            self.focus_flags
1384                .iter()
1385                .enumerate()
1386                .find(|(_, v)| v.get())
1387                .map(|(i, _)| self.navigable[i])
1388        }
1389
1390        /// Currently focused.
1391        pub(super) fn focused(&self) -> Option<FocusFlag> {
1392            self.focus_flags.iter().find(|v| v.get()).cloned()
1393        }
1394
1395        /// Last lost focus.
1396        pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1397            self.focus_flags.iter().find(|v| v.lost()).cloned()
1398        }
1399
1400        /// Current gained focus.
1401        pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1402            self.focus_flags.iter().find(|v| v.gained()).cloned()
1403        }
1404
1405        /// First navigable flag starting at n.
1406        fn first_navigable(&self, start: usize) -> Option<usize> {
1407            focus_debug!(
1408                self.log,
1409                "first navigable, start at {:?} ",
1410                if start < self.focus_flags.len() {
1411                    self.focus_flags[start].name()
1412                } else {
1413                    "beginning"
1414                }
1415            );
1416            for n in start..self.focus_flags.len() {
1417                if matches!(
1418                    self.navigable[n],
1419                    Navigation::Reach
1420                        | Navigation::ReachLeaveBack
1421                        | Navigation::ReachLeaveFront
1422                        | Navigation::Regular
1423                ) {
1424                    focus_debug!(self.log, "    -> {:?}", self.focus_flags[n].name());
1425                    return Some(n);
1426                }
1427            }
1428            focus_debug!(self.log, "    -> no first");
1429            None
1430        }
1431
1432        /// Next navigable flag, starting at start.
1433        fn next_navigable(&self, start: usize) -> usize {
1434            focus_debug!(
1435                self.log,
1436                "next navigable after {:?}",
1437                if start < self.focus_flags.len() {
1438                    self.focus_flags[start].name()
1439                } else {
1440                    "last"
1441                }
1442            );
1443
1444            let mut n = start;
1445            loop {
1446                n = if n + 1 < self.focus_flags.len() {
1447                    n + 1
1448                } else {
1449                    0
1450                };
1451                if matches!(
1452                    self.navigable[n],
1453                    Navigation::Reach
1454                        | Navigation::ReachLeaveBack
1455                        | Navigation::ReachLeaveFront
1456                        | Navigation::Regular
1457                ) {
1458                    focus_debug!(self.log, "    -> {}:{:?}", n, self.focus_flags[n].name());
1459                    return n;
1460                }
1461                if n == start {
1462                    focus_debug!(self.log, "    -> {}:end at start", n);
1463                    return n;
1464                }
1465            }
1466        }
1467
1468        /// Previous navigable flag, starting at start.
1469        fn prev_navigable(&self, start: usize) -> usize {
1470            focus_debug!(
1471                self.log,
1472                "prev navigable before {:?}",
1473                self.focus_flags[start].name()
1474            );
1475
1476            let mut n = start;
1477            loop {
1478                n = if n > 0 {
1479                    n - 1
1480                } else {
1481                    self.focus_flags.len() - 1
1482                };
1483                if matches!(
1484                    self.navigable[n],
1485                    Navigation::Reach
1486                        | Navigation::ReachLeaveBack
1487                        | Navigation::ReachLeaveFront
1488                        | Navigation::Regular
1489                ) {
1490                    focus_debug!(self.log, "    -> {}:{:?}", n, self.focus_flags[n].name());
1491                    return n;
1492                }
1493                if n == start {
1494                    focus_debug!(self.log, "    -> {}:end at start", n);
1495                    return n;
1496                }
1497            }
1498        }
1499
1500        /// Debug destructuring.
1501        #[allow(clippy::type_complexity)]
1502        pub(super) fn clone_destruct(
1503            &self,
1504        ) -> (
1505            Vec<FocusFlag>,
1506            Vec<bool>,
1507            Vec<(Rect, u16)>,
1508            Vec<Navigation>,
1509            Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1510        ) {
1511            (
1512                self.focus_flags.clone(),
1513                self.duplicate.clone(),
1514                self.areas.clone(),
1515                self.navigable.clone(),
1516                self.containers
1517                    .iter()
1518                    .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1519                    .collect::<Vec<_>>(),
1520            )
1521        }
1522    }
1523
1524    #[cfg(test)]
1525    mod test {
1526        use crate::focus::core::FocusCore;
1527        use crate::{FocusBuilder, FocusFlag, HasFocus};
1528        use ratatui::layout::Rect;
1529
1530        #[test]
1531        fn test_change() {
1532            assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1533            assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1534
1535            assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1536            assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1537            assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1538            assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1539            assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1540
1541            assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1542            assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1543            assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1544            assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1545            assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1546
1547            assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1548            assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1549            assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1550            assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1551            assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1552
1553            assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1554            assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1555            assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1556            assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1557            assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1558        }
1559
1560        #[test]
1561        #[should_panic]
1562        fn test_double_insert() {
1563            let a = FocusFlag::named("a");
1564            let b = FocusFlag::named("b");
1565
1566            let mut fb = FocusBuilder::new(None);
1567            fb.widget(&a);
1568            fb.widget(&b);
1569            fb.widget(&a);
1570            fb.build();
1571        }
1572
1573        #[test]
1574        fn test_insert_remove() {
1575            let a = FocusFlag::named("a");
1576            let b = FocusFlag::named("b");
1577            let c = FocusFlag::named("c");
1578            let d = FocusFlag::named("d");
1579            let e = FocusFlag::named("e");
1580            let f = FocusFlag::named("f");
1581            let g = FocusFlag::named("g");
1582            let h = FocusFlag::named("h");
1583            let i = FocusFlag::named("i");
1584
1585            let mut fb = FocusBuilder::new(None);
1586            fb.widget(&a);
1587            fb.widget(&b);
1588            fb.widget(&c);
1589            let ff = fb.build();
1590            assert_eq!(ff.core.focus_flags[0], a);
1591            assert_eq!(ff.core.focus_flags[1], b);
1592            assert_eq!(ff.core.focus_flags[2], c);
1593
1594            let cc = FocusFlag::named("cc");
1595            let mut fb = FocusBuilder::new(None);
1596            fb.widget(&a);
1597            let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1598            fb.widget(&d);
1599            fb.widget(&e);
1600            fb.widget(&f);
1601            fb.end(cc_end);
1602            fb.widget(&b);
1603            fb.widget(&c);
1604            let mut ff = fb.build();
1605            assert_eq!(ff.core.focus_flags[0], a);
1606            assert_eq!(ff.core.focus_flags[1], d);
1607            assert_eq!(ff.core.focus_flags[2], e);
1608            assert_eq!(ff.core.focus_flags[3], f);
1609            assert_eq!(ff.core.focus_flags[4], b);
1610            assert_eq!(ff.core.focus_flags[5], c);
1611            assert_eq!(ff.core.containers[0].1, 1..4);
1612
1613            struct DD {
1614                dd: FocusFlag,
1615                g: FocusFlag,
1616                h: FocusFlag,
1617                i: FocusFlag,
1618            }
1619
1620            impl HasFocus for DD {
1621                fn build(&self, fb: &mut FocusBuilder) {
1622                    let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1623                    fb.widget(&self.g);
1624                    fb.widget(&self.h);
1625                    fb.widget(&self.i);
1626                    fb.end(tag);
1627                }
1628
1629                fn focus(&self) -> FocusFlag {
1630                    self.dd.clone()
1631                }
1632
1633                fn area(&self) -> Rect {
1634                    Rect::default()
1635                }
1636            }
1637
1638            let dd = DD {
1639                dd: FocusFlag::named("dd"),
1640                g: g.clone(),
1641                h: h.clone(),
1642                i: i.clone(),
1643            };
1644            ff.replace_container(&cc, &dd);
1645            assert_eq!(ff.core.focus_flags[0], a);
1646            assert_eq!(ff.core.focus_flags[1], g);
1647            assert_eq!(ff.core.focus_flags[2], h);
1648            assert_eq!(ff.core.focus_flags[3], i);
1649            assert_eq!(ff.core.focus_flags[4], b);
1650            assert_eq!(ff.core.focus_flags[5], c);
1651            assert_eq!(ff.core.containers[0].1, 1..4);
1652        }
1653    }
1654}
1655
1656impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1657    #[inline(always)]
1658    fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1659        match event {
1660            ct_event!(keycode press Tab) => {
1661                focus_debug!(
1662                    self.core.log,
1663                    "Tab {:?}",
1664                    self.focused().map(|v| v.name().to_string())
1665                );
1666                let r = self.next().into();
1667                focus_debug!(
1668                    self.core.log,
1669                    "    -> {:?}",
1670                    self.focused().map(|v| v.name().to_string())
1671                );
1672                r
1673            }
1674            ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1675                focus_debug!(
1676                    self.core.log,
1677                    "BackTab {:?}",
1678                    self.focused().map(|v| v.name().to_string())
1679                );
1680                let r = self.prev().into();
1681                focus_debug!(
1682                    self.core.log,
1683                    "    -> {:?}",
1684                    self.focused().map(|v| v.name().to_string())
1685                );
1686                r
1687            }
1688            _ => self.handle(event, MouseOnly),
1689        }
1690    }
1691}
1692
1693impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1694    #[inline(always)]
1695    fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1696        match event {
1697            ct_event!(mouse down Left for column, row) => {
1698                focus_debug!(self.core.log, "mouse down {},{}", column, row);
1699                if self.focus_at(*column, *row) {
1700                    focus_debug!(
1701                        self.core.log,
1702                        "    -> {:?}",
1703                        self.focused().map(|v| v.name().to_string())
1704                    );
1705                    Outcome::Changed
1706                } else {
1707                    self.reset_lost_gained();
1708                    Outcome::Continue
1709                }
1710            }
1711            _ => {
1712                self.reset_lost_gained();
1713                Outcome::Continue
1714            }
1715        }
1716    }
1717}
1718
1719/// Handle all events.
1720#[inline(always)]
1721pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1722    HandleEvent::handle(focus, event, Regular)
1723}