1use crate::focus::core::FocusCore;
2use crate::{FocusFlag, HasFocus, Navigation};
3pub use core::FocusBuilder;
4use rat_event::{HandleEvent, MouseOnly, Outcome, Regular, ct_event};
5use ratatui::layout::Rect;
6use std::ops::Range;
7
8#[derive(Default, Debug, Clone)]
15pub struct Focus {
16 last: FocusCore,
17 core: FocusCore,
18}
19
20macro_rules! focus_debug {
21 ($log:expr, $($arg:tt)+) => {
22 if $log.get() {
23 log::log!(log::Level::Debug, $($arg)+);
24 }
25 }
26}
27
28impl Focus {
29 pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
37 focus_debug!(
38 self.core.log,
39 "focus remove container {:?} ",
40 container.focus().name()
41 );
42 let flag = container.focus();
43 if self.core.is_container(&flag) {
44 if let Some((cidx, _)) = self.core.container_index_of(&flag) {
45 self.core.remove_container(cidx).reset();
46 focus_debug!(self.core.log, " -> removed");
47 } else {
48 focus_debug!(self.core.log, " => container not found");
49 }
50 } else {
51 focus_debug!(self.core.log, " => no container flag");
52 }
53 }
54
55 pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
66 focus_debug!(
67 self.core.log,
68 "focus update container {:?} ",
69 container.focus().name()
70 );
71 let flag = container.focus();
72 if self.core.is_container(&flag) {
73 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
74 let removed = self.core.remove_container(cidx);
75
76 let mut b = FocusBuilder::new(Some(Focus {
77 last: Default::default(),
78 core: removed,
79 }));
80 b.widget(container);
81 let insert = b.build();
82
83 self.core.insert_container(range.start, cidx, insert.core);
84
85 focus_debug!(self.core.log, " -> updated");
86 } else {
87 focus_debug!(self.core.log, " => container not found");
88 }
89 } else {
90 focus_debug!(self.core.log, " => no container flag");
91 }
92 }
93
94 pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
108 focus_debug!(
109 self.core.log,
110 "focus replace container {:?} with {:?} ",
111 container.focus().name(),
112 new.focus().name()
113 );
114 let flag = container.focus();
115 if self.core.is_container(&flag) {
116 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
117 let removed = self.core.remove_container(cidx);
118
119 let mut b = FocusBuilder::new(Some(Focus {
120 last: Default::default(),
121 core: removed,
122 }));
123 b.widget(new);
124 let insert = b.build();
125
126 self.core.insert_container(range.start, cidx, insert.core);
127
128 focus_debug!(self.core.log, " -> replaced");
129 } else {
130 focus_debug!(self.core.log, " => container not found");
131 }
132 } else {
133 focus_debug!(self.core.log, " => no container flag");
134 }
135 }
136
137 pub fn enable_log(&self) {
139 self.core.log.set(true);
140 self.last.log.set(true);
141 }
142
143 pub fn disable_log(&self) {
145 self.core.log.set(false);
146 self.last.log.set(false);
147 }
148
149 #[inline]
154 pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
155 focus_debug!(
156 self.core.log,
157 "focus no_lost {:?}",
158 widget_state.focus().name()
159 );
160 let flag = widget_state.focus();
161 if self.core.is_widget(&flag) {
162 if let Some(n) = self.core.index_of(&flag) {
163 self.core.focus_idx(n, false);
164 } else {
165 focus_debug!(self.core.log, " => widget not found");
166 }
167 } else if self.core.is_container(&flag) {
168 if let Some((_idx, range)) = self.core.container_index_of(&flag) {
169 self.core.focus_idx(range.start, false);
170 focus_debug!(self.core.log, " -> focused");
171 } else {
172 focus_debug!(self.core.log, " => container not found");
173 }
174 } else {
175 focus_debug!(self.core.log, " => not a valid widget");
176 }
177 }
178
179 #[inline]
186 pub fn by_widget_id(&self, widget_id: usize) {
187 let widget_state = self.core.find_widget_id(widget_id);
188 focus_debug!(self.core.log, "focus {:?} -> {:?}", widget_id, widget_state);
189 let Some(widget_state) = widget_state else {
190 return;
191 };
192
193 let flag = widget_state.focus();
194 if self.core.is_widget(&flag) {
195 if let Some(n) = self.core.index_of(&flag) {
196 self.core.focus_idx(n, true);
197 } else {
198 focus_debug!(self.core.log, " => widget not found");
199 }
200 } else if self.core.is_container(&flag) {
201 if let Some((_idx, range)) = self.core.container_index_of(&flag) {
202 self.core.focus_idx(range.start, true);
203 focus_debug!(self.core.log, " -> focused");
204 } else {
205 focus_debug!(self.core.log, " => container not found");
206 }
207 } else {
208 focus_debug!(self.core.log, " => not a valid widget");
209 }
210 }
211
212 #[inline]
219 pub fn focus(&self, widget_state: &'_ dyn HasFocus) {
220 focus_debug!(self.core.log, "focus {:?}", widget_state.focus().name());
221 let flag = widget_state.focus();
222 if self.core.is_widget(&flag) {
223 if let Some(n) = self.core.index_of(&flag) {
224 self.core.focus_idx(n, true);
225 } else {
226 focus_debug!(self.core.log, " => widget not found");
227 }
228 } else if self.core.is_container(&flag) {
229 if let Some((_idx, range)) = self.core.container_index_of(&flag) {
230 self.core.focus_idx(range.start, true);
231 focus_debug!(self.core.log, " -> focused");
232 } else {
233 focus_debug!(self.core.log, " => container not found");
234 }
235 } else {
236 focus_debug!(self.core.log, " => not a valid widget");
237 }
238 }
239
240 #[inline]
243 pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
244 focus_debug!(
245 self.core.log,
246 "expel from widget {:?}",
247 widget_state.focus().name()
248 );
249 let flag = widget_state.focus();
250 if self.core.is_widget(&flag) {
251 if self.core.index_of(&flag).is_some() {
252 if widget_state.is_focused() {
253 self.core.next();
254 if widget_state.is_focused() {
255 focus_debug!(self.core.log, " -> no other focus, cleared");
256 flag.clear();
257 } else {
258 focus_debug!(self.core.log, " -> expelled");
259 }
260 } else {
261 focus_debug!(self.core.log, " => widget not focused");
262 }
263 } else {
264 focus_debug!(self.core.log, " => widget not found");
265 }
266 } else if self.core.is_container(&flag) {
267 if flag.is_focused() {
268 self.core.expel_container(flag);
269 } else {
270 focus_debug!(self.core.log, " => container not focused");
271 }
272 } else {
273 focus_debug!(self.core.log, " => not a valid widget");
274 }
275 }
276
277 #[inline(always)]
283 pub fn focused(&self) -> Option<FocusFlag> {
284 self.core.focused()
285 }
286
287 #[inline(always)]
291 pub fn focused_name(&self) -> Option<String> {
292 self.core.focused().map(|v| v.name().to_string())
293 }
294
295 #[inline(always)]
297 pub fn navigation(&self) -> Option<Navigation> {
298 self.core.navigation()
299 }
300
301 #[inline(always)]
307 pub fn lost_focus(&self) -> Option<FocusFlag> {
308 self.core.lost_focus()
309 }
310
311 #[inline(always)]
317 pub fn gained_focus(&self) -> Option<FocusFlag> {
318 self.core.gained_focus()
319 }
320
321 #[inline(always)]
324 pub fn reset_lost_gained(&self) {
325 self.core.reset_lost_gained();
326 }
327
328 #[inline(always)]
330 pub fn focus_at(&self, col: u16, row: u16) -> bool {
331 focus_debug!(self.core.log, "focus at {},{}", col, row);
332 match self.navigation() {
333 Some(Navigation::Lock) => {
334 focus_debug!(self.core.log, " -> locked");
335 false
336 }
337 _ => self.core.focus_at(col, row),
338 }
339 }
340
341 #[inline(always)]
346 pub fn first(&self) {
347 focus_debug!(self.core.log, "focus first");
348 self.core.first();
349 }
350
351 #[inline]
356 pub fn first_in(&self, container: &'_ dyn HasFocus) {
357 focus_debug!(
358 self.core.log,
359 "focus first in container {:?} ",
360 container.focus().name()
361 );
362 let flag = container.focus();
363 if self.core.is_container(&flag) {
364 self.core.first_container(&flag);
365 } else if self.core.is_widget(&flag) {
366 if let Some(n) = self.core.index_of(&flag) {
367 self.core.focus_idx(n, true);
368 } else {
369 focus_debug!(self.core.log, " => widget not found");
370 }
371 } else {
372 focus_debug!(self.core.log, " -> not a container");
373 }
374 }
375
376 #[inline(always)]
381 pub fn none(&self) {
382 focus_debug!(self.core.log, "focus none");
383 self.core.none();
384 focus_debug!(self.core.log, " -> done");
385 }
386
387 #[inline]
394 pub fn next(&self) -> bool {
395 match self.navigation() {
396 None => {
397 self.first();
398 true
399 }
400 Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
401 focus_debug!(
402 self.core.log,
403 "next after {:?}",
404 self.core
405 .focused()
406 .map(|v| v.name().to_string())
407 .unwrap_or("None".into())
408 );
409 self.core.next()
410 }
411 v => {
412 focus_debug!(
413 self.core.log,
414 "next after {:?}, but navigation says {:?}",
415 self.core
416 .focused()
417 .map(|v| v.name().to_string())
418 .unwrap_or("None".into()),
419 v
420 );
421 false
422 }
423 }
424 }
425
426 #[inline]
433 pub fn prev(&self) -> bool {
434 match self.navigation() {
435 None => {
436 self.first();
437 true
438 }
439 Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
440 focus_debug!(
441 self.core.log,
442 "prev before {:?}",
443 self.core
444 .focused()
445 .map(|v| v.name().to_string())
446 .unwrap_or("None".into())
447 );
448 self.core.prev()
449 }
450 v => {
451 focus_debug!(
452 self.core.log,
453 "prev before {:?}, but navigation says {:?}",
454 self.core
455 .focused()
456 .map(|v| v.name().to_string())
457 .unwrap_or("None".into()),
458 v
459 );
460 false
461 }
462 }
463 }
464
465 #[inline]
474 pub fn next_force(&self) -> bool {
475 match self.navigation() {
476 None => {
477 self.first();
478 true
479 }
480 Some(
481 Navigation::Leave
482 | Navigation::Reach
483 | Navigation::ReachLeaveFront
484 | Navigation::ReachLeaveBack
485 | Navigation::Regular,
486 ) => {
487 focus_debug!(
488 self.core.log,
489 "force next after {:?}",
490 self.core.focused().map(|v| v.name().to_string())
491 );
492 self.core.next()
493 }
494 v => {
495 focus_debug!(
496 self.core.log,
497 "force next after {:?}, but navigation says {:?}",
498 self.core.focused().map(|v| v.name().to_string()),
499 v
500 );
501 false
502 }
503 }
504 }
505
506 #[inline]
516 pub fn prev_force(&self) -> bool {
517 match self.navigation() {
518 None => {
519 self.first();
520 true
521 }
522 Some(
523 Navigation::Leave
524 | Navigation::Reach
525 | Navigation::ReachLeaveFront
526 | Navigation::ReachLeaveBack
527 | Navigation::Regular,
528 ) => {
529 focus_debug!(
530 self.core.log,
531 "force prev before {:?}",
532 self.core.focused().map(|v| v.name().to_string())
533 );
534 self.core.prev()
535 }
536 v => {
537 focus_debug!(
538 self.core.log,
539 "force prev before {:?}, but navigation says {:?}",
540 self.core.focused().map(|v| v.name().to_string()),
541 v
542 );
543 false
544 }
545 }
546 }
547
548 #[allow(clippy::type_complexity)]
550 pub fn clone_destruct(
551 &self,
552 ) -> (
553 Vec<FocusFlag>,
554 Vec<bool>,
555 Vec<(Rect, u16)>,
556 Vec<Navigation>,
557 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
558 ) {
559 self.core.clone_destruct()
560 }
561}
562
563mod core {
564 use crate::{Focus, FocusFlag, HasFocus, Navigation};
565 use fxhash::FxBuildHasher;
566 use ratatui::layout::Rect;
567 use std::cell::Cell;
568 use std::collections::HashSet;
569 use std::ops::Range;
570
571 #[derive(Debug, Default)]
573 pub struct FocusBuilder {
574 last: FocusCore,
575
576 log: Cell<bool>,
577
578 z_base: u16,
586
587 focus_ids: HashSet<usize, FxBuildHasher>,
589 focus_flags: Vec<FocusFlag>,
590 duplicate: Vec<bool>,
591 areas: Vec<(Rect, u16)>,
592 navigable: Vec<Navigation>,
593 container_ids: HashSet<usize, FxBuildHasher>,
594 containers: Vec<(Container, Range<usize>)>,
595 }
596
597 impl FocusBuilder {
598 pub fn new(last: Option<Focus>) -> FocusBuilder {
599 if let Some(mut last) = last {
600 last.last.clear();
602
603 Self {
604 last: last.core,
605 log: Default::default(),
606 z_base: 0,
607 focus_ids: last.last.focus_ids,
608 focus_flags: last.last.focus_flags,
609 duplicate: last.last.duplicate,
610 areas: last.last.areas,
611 navigable: last.last.navigable,
612 container_ids: last.last.container_ids,
613 containers: last.last.containers,
614 }
615 } else {
616 Self {
617 last: FocusCore::default(),
618 log: Default::default(),
619 z_base: Default::default(),
620 focus_ids: Default::default(),
621 focus_flags: Default::default(),
622 duplicate: Default::default(),
623 areas: Default::default(),
624 navigable: Default::default(),
625 container_ids: Default::default(),
626 containers: Default::default(),
627 }
628 }
629 }
630
631 pub fn build_for(container: &dyn HasFocus) -> Focus {
643 let mut b = FocusBuilder::new(None);
644 b.widget(container);
645 b.build()
646 }
647
648 pub fn rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
655 let mut b = FocusBuilder::new(old);
656 b.widget(container);
657 b.build()
658 }
659
660 pub fn enable_log(&self) {
662 self.log.set(true);
663 }
664
665 pub fn disable_log(&self) {
667 self.log.set(false);
668 }
669
670 pub fn widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
676 widget.build(self);
677 self
678 }
679
680 #[allow(clippy::collapsible_else_if)]
692 pub fn widget_navigate(
693 &mut self,
694 widget: &dyn HasFocus,
695 navigation: Navigation,
696 ) -> &mut Self {
697 widget.build(self);
698
699 if let Some(idx) = self.focus_flags.iter().position(|v| *v == widget.focus()) {
701 focus_debug!(
702 self.log,
703 "override navigation for {:?} with {:?}",
704 widget.focus(),
705 navigation
706 );
707
708 self.navigable[idx] = navigation;
709 } else {
710 if self.container_ids.contains(&widget.focus().widget_id()) {
711 focus_debug!(
712 self.log,
713 "FAIL to override navigation for {:?}. This is a container.",
714 widget.focus(),
715 );
716 } else {
717 focus_debug!(
718 self.log,
719 "FAIL to override navigation for {:?}. Widget doesn't use this focus-flag",
720 widget.focus(),
721 );
722 }
723 }
724
725 self
726 }
727
728 #[inline]
732 pub fn widgets<const N: usize>(&mut self, widgets: [&dyn HasFocus; N]) -> &mut Self {
733 for widget in widgets {
734 widget.build(self);
735 }
736 self
737 }
738
739 #[must_use]
752 pub fn start(&mut self, container: &dyn HasFocus) -> FocusFlag {
753 self.start_with_flags(container.focus(), container.area(), container.area_z())
754 }
755
756 pub fn end(&mut self, tag: FocusFlag) {
758 focus_debug!(self.log, "end container {:?}", tag);
759 assert!(self.container_ids.contains(&tag.widget_id()));
760
761 for (c, r) in self.containers.iter_mut().rev() {
762 if c.container_flag != tag {
763 if !c.complete {
764 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
765 }
766 } else {
767 r.end = self.focus_flags.len();
768 c.complete = true;
769
770 focus_debug!(self.log, "container range {:?}", r);
771
772 self.z_base -= c.delta_z;
773
774 break;
775 }
776 }
777 }
778
779 pub fn leaf_widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
782 self.widget_with_flags(
783 widget.focus(),
784 widget.area(),
785 widget.area_z(),
786 widget.navigable(),
787 );
788 self
789 }
790
791 pub fn widget_with_flags(
804 &mut self,
805 focus: FocusFlag,
806 area: Rect,
807 area_z: u16,
808 navigable: Navigation,
809 ) {
810 let duplicate = self.focus_ids.contains(&focus.widget_id());
811
812 if duplicate {
815 assert!(matches!(navigable, Navigation::Mouse | Navigation::None))
816 }
817
818 focus_debug!(self.log, "widget {:?}", focus);
819
820 self.focus_ids.insert(focus.widget_id());
821 self.focus_flags.push(focus);
822 self.duplicate.push(duplicate);
823 self.areas.push((area, self.z_base + area_z));
824 self.navigable.push(navigable);
825 }
826
827 #[must_use]
839 pub fn start_with_flags(
840 &mut self,
841 container_flag: FocusFlag,
842 area: Rect,
843 area_z: u16,
844 ) -> FocusFlag {
845 focus_debug!(self.log, "start container {:?}", container_flag);
846
847 assert!(!self.container_ids.contains(&container_flag.widget_id()));
849
850 self.z_base += area_z;
851
852 let len = self.focus_flags.len();
853 self.container_ids.insert(container_flag.widget_id());
854 self.containers.push((
855 Container {
856 container_flag: container_flag.clone(),
857 area: (area, self.z_base),
858 delta_z: area_z,
859 complete: false,
860 },
861 len..len,
862 ));
863
864 container_flag
865 }
866
867 pub fn build(mut self) -> Focus {
872 for v in &self.last.focus_flags {
874 if !self.focus_ids.contains(&v.widget_id()) {
875 v.clear();
876 }
877 }
878 for (v, _) in &self.last.containers {
879 let have_container = self
880 .containers
881 .iter()
882 .any(|(c, _)| v.container_flag == c.container_flag);
883 if !have_container {
884 v.container_flag.clear();
885 }
886 }
887 self.last.clear();
888
889 for (c, _) in self.containers.iter_mut().rev() {
891 if !c.complete {
892 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
893 }
894 }
895
896 let log = self.last.log.get();
897
898 Focus {
899 last: self.last,
900 core: FocusCore {
901 log: Cell::new(log),
902 focus_ids: self.focus_ids,
903 focus_flags: self.focus_flags,
904 duplicate: self.duplicate,
905 areas: self.areas,
906 navigable: self.navigable,
907 container_ids: self.container_ids,
908 containers: self.containers,
909 },
910 }
911 }
912 }
913
914 #[derive(Debug, Clone)]
916 struct Container {
917 container_flag: FocusFlag,
921 area: (Rect, u16),
924 delta_z: u16,
926 complete: bool,
928 }
929
930 #[derive(Debug, Default, Clone)]
932 pub(super) struct FocusCore {
933 pub(super) log: Cell<bool>,
935
936 focus_ids: HashSet<usize, FxBuildHasher>,
938 focus_flags: Vec<FocusFlag>,
940 duplicate: Vec<bool>,
943 areas: Vec<(Rect, u16)>,
946 navigable: Vec<Navigation>,
948 container_ids: HashSet<usize, FxBuildHasher>,
950 containers: Vec<(Container, Range<usize>)>,
955 }
956
957 impl FocusCore {
958 pub(super) fn clear(&mut self) {
960 self.focus_ids.clear();
961 self.focus_flags.clear();
962 self.duplicate.clear();
963 self.areas.clear();
964 self.navigable.clear();
965 self.container_ids.clear();
966 self.containers.clear();
967 }
968
969 pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
971 self.focus_flags
972 .iter()
973 .find(|v| widget_id == v.widget_id())
974 .cloned()
975 }
976
977 pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
979 self.focus_ids.contains(&focus_flag.widget_id())
980 }
981
982 pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
984 self.focus_flags
985 .iter()
986 .enumerate()
987 .find(|(_, f)| *f == focus_flag)
988 .map(|(idx, _)| idx)
989 }
990
991 pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
993 self.container_ids.contains(&focus_flag.widget_id())
994 }
995
996 pub(super) fn container_index_of(
998 &self,
999 container_flag: &FocusFlag,
1000 ) -> Option<(usize, Range<usize>)> {
1001 self.containers
1002 .iter()
1003 .enumerate()
1004 .find(|(_, (c, _))| &c.container_flag == container_flag)
1005 .map(|(idx, (_, range))| (idx, range.clone()))
1006 }
1007
1008 pub(super) fn insert_container(
1013 &mut self,
1014 idx: usize,
1015 cidx: usize,
1016 mut container: FocusCore,
1017 ) {
1018 for c in &self.focus_flags {
1019 for d in &container.focus_flags {
1020 assert_ne!(c, d);
1021 }
1022 }
1023
1024 let start = idx;
1026 let end = idx + container.focus_flags.len();
1027
1028 self.focus_ids.extend(container.focus_ids.iter());
1029 self.focus_flags
1030 .splice(idx..idx, container.focus_flags.drain(..));
1031 self.duplicate
1032 .splice(idx..idx, container.duplicate.drain(..));
1033 self.areas.splice(idx..idx, container.areas.drain(..));
1034 self.navigable
1035 .splice(idx..idx, container.navigable.drain(..));
1036
1037 for (_, r) in &mut self.containers {
1039 *r = Self::expand(start..end, r.clone());
1040 }
1041 self.containers.splice(
1043 cidx..cidx,
1044 container
1045 .containers
1046 .drain(..)
1047 .map(|(c, r)| (c, Self::shift(start, r))),
1048 );
1049 self.container_ids.extend(container.container_ids.iter());
1050 }
1051
1052 pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1055 let crange = self.containers[cidx].1.clone();
1056
1057 let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1059 let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1060 for f in focus_flags.iter() {
1061 self.focus_ids.remove(&f.widget_id());
1062 focus_ids.insert(f.widget_id());
1063 }
1064 let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1065 let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1066 let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1067 let sub_containers = self
1068 .containers
1069 .iter()
1070 .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1071 .cloned()
1072 .collect::<Vec<_>>();
1073 self.containers
1075 .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1076 let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1077 for (sc, _) in sub_containers.iter() {
1078 self.container_ids.remove(&sc.container_flag.widget_id());
1079 sub_container_ids.insert(sc.container_flag.widget_id());
1080 }
1081
1082 for (_, r) in &mut self.containers {
1084 *r = Self::shrink(crange.start..crange.end, r.clone());
1085 }
1086
1087 FocusCore {
1088 log: Cell::new(false),
1089 focus_ids,
1090 focus_flags,
1091 duplicate,
1092 areas,
1093 navigable,
1094 container_ids: sub_container_ids,
1095 containers: sub_containers,
1096 }
1097 }
1098
1099 fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1101 range.start + n..range.end + n
1102 }
1103
1104 fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1106 let len = insert.end - insert.start;
1107
1108 if range.start >= insert.start {
1109 range.start += len;
1110 }
1111 if range.end > insert.start {
1112 range.end += len;
1113 }
1114 range
1115 }
1116
1117 fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1119 let len = remove.end - remove.start;
1120
1121 if range.start < remove.start {
1122 } else if range.start >= remove.start && range.start <= remove.end {
1124 range.start = remove.start;
1125 } else {
1126 range.start -= len;
1127 }
1128
1129 if range.end < remove.start {
1130 } else if range.end >= remove.start && range.end <= remove.end {
1132 range.end = remove.start;
1133 } else {
1134 range.end -= len;
1135 }
1136
1137 range
1138 }
1139
1140 fn __start_change(&self, set_lost: bool) {
1143 for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1144 if *duplicate {
1145 continue;
1147 }
1148 if set_lost {
1149 f.set_lost(f.get());
1150 } else {
1151 f.set_lost(false);
1152 }
1153 f.set_gained(false);
1154 f.set(false);
1155 }
1156 }
1157
1158 fn __focus(&self, n: usize, set_lost: bool) -> bool {
1161 if let Some(f) = self.focus_flags.get(n) {
1162 focus_debug!(self.log, " -> focus {}:{:?}", n, f.name());
1163 f.set(true);
1164 if set_lost {
1165 if f.lost() {
1166 f.set_lost(false);
1169 f.set_gained(false);
1170 false
1171 } else {
1172 f.set_gained(true);
1173 true
1174 }
1175 } else {
1176 false
1177 }
1178 } else {
1179 false
1180 }
1181 }
1182
1183 fn __accumulate(&self) {
1185 for (f, r) in &self.containers {
1186 let mut any_gained = false;
1187 let mut any_lost = false;
1188 let mut any_focused = false;
1189
1190 for idx in r.clone() {
1191 any_gained |= self.focus_flags[idx].gained();
1192 any_lost |= self.focus_flags[idx].lost();
1193 any_focused |= self.focus_flags[idx].get();
1194 }
1195
1196 f.container_flag.set(any_focused);
1197 f.container_flag.set_lost(any_lost && !any_gained);
1198 f.container_flag.set_gained(any_gained && !any_lost);
1199 }
1200 }
1201
1202 pub(super) fn reset(&self) {
1204 for f in self.focus_flags.iter() {
1205 f.set(false);
1206 f.set_lost(false);
1207 f.set_gained(false);
1208 }
1209 for (f, _) in self.containers.iter() {
1210 f.container_flag.set(false);
1211 f.container_flag.set_gained(false);
1212 f.container_flag.set_lost(false);
1213 }
1214 }
1215
1216 pub(super) fn reset_lost_gained(&self) {
1218 for f in self.focus_flags.iter() {
1219 f.set_lost(false);
1220 f.set_gained(false);
1221 }
1222 for (f, _) in self.containers.iter() {
1223 f.container_flag.set_gained(false);
1224 f.container_flag.set_lost(false);
1225 }
1226 }
1227
1228 pub(super) fn first(&self) {
1230 if let Some(n) = self.first_navigable(0) {
1231 self.__start_change(true);
1232 self.__focus(n, true);
1233 self.__accumulate();
1234 } else {
1235 focus_debug!(self.log, " -> no navigable widget");
1236 }
1237 }
1238
1239 pub(super) fn none(&self) {
1241 self.__start_change(true);
1242 self.__accumulate();
1243 }
1244
1245 pub(super) fn first_container(&self, container: &FocusFlag) {
1247 if let Some((_idx, range)) = self.container_index_of(container) {
1248 if let Some(n) = self.first_navigable(range.start) {
1249 if n < range.end {
1250 self.__start_change(true);
1251 self.__focus(n, true);
1252 self.__accumulate();
1253 } else {
1254 focus_debug!(self.log, " -> no navigable widget for container");
1255 }
1256 } else {
1257 focus_debug!(self.log, " -> no navigable widget");
1258 }
1259 } else {
1260 focus_debug!(self.log, " => container not found");
1261 }
1262 }
1263
1264 pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1266 self.__start_change(set_lost);
1267 self.__focus(n, set_lost);
1268 self.__accumulate();
1269 }
1270
1271 pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1275 let pos = (col, row).into();
1276
1277 enum ZOrder {
1278 Widget(usize),
1279 Container(usize),
1280 }
1281
1282 let mut z_order: Option<(ZOrder, u16)> = None;
1284 for (idx, (sub, _)) in self.containers.iter().enumerate() {
1287 if sub.area.0.contains(pos) {
1288 focus_debug!(
1289 self.log,
1290 " container area-match {:?}",
1291 sub.container_flag.name()
1292 );
1293
1294 z_order = if let Some(zz) = z_order {
1295 if zz.1 <= sub.area.1 {
1296 Some((ZOrder::Container(idx), sub.area.1))
1297 } else {
1298 Some(zz)
1299 }
1300 } else {
1301 Some((ZOrder::Container(idx), sub.area.1))
1302 };
1303 }
1304 }
1305 for (idx, area) in self.areas.iter().enumerate() {
1307 if area.0.contains(pos) {
1308 focus_debug!(
1309 self.log,
1310 " area-match {:?}",
1311 self.focus_flags[idx].name()
1312 );
1313
1314 z_order = if let Some(zz) = z_order {
1315 if zz.1 <= area.1 {
1316 Some((ZOrder::Widget(idx), area.1))
1317 } else {
1318 Some(zz)
1319 }
1320 } else {
1321 Some((ZOrder::Widget(idx), area.1))
1322 };
1323 }
1324 }
1325
1326 if let Some((idx, _)) = z_order {
1328 match idx {
1329 ZOrder::Widget(idx) => {
1330 if self.navigable[idx] != Navigation::None {
1331 self.__start_change(true);
1332 let r = self.__focus(idx, true);
1333 self.__accumulate();
1334 return r;
1335 } else {
1336 focus_debug!(
1337 self.log,
1338 " -> not mouse reachable {:?}",
1339 self.focus_flags[idx].name()
1340 );
1341 return false;
1342 }
1343 }
1344 ZOrder::Container(idx) => {
1345 let range = &self.containers[idx].1;
1346 if let Some(n) = self.first_navigable(range.start) {
1347 self.__start_change(true);
1348 let r = self.__focus(n, true);
1349 self.__accumulate();
1350 return r;
1351 }
1352 }
1353 }
1354 }
1355
1356 focus_debug!(self.log, " -> no widget at pos");
1358
1359 false
1360 }
1361
1362 pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1364 if let Some((_idx, range)) = self.container_index_of(&flag) {
1365 self.__start_change(true);
1366 let n = self.next_navigable(range.end);
1367 self.__focus(n, true);
1368 self.__accumulate();
1369
1370 if flag.is_focused() {
1372 focus_debug!(self.log, " -> focus not usable. cleared");
1373 self.none();
1374 } else {
1375 focus_debug!(self.log, " -> expelled.");
1376 }
1377 true
1378 } else {
1379 focus_debug!(self.log, " => container not found");
1380 false
1381 }
1382 }
1383
1384 pub(super) fn next(&self) -> bool {
1386 self.__start_change(true);
1387 for (n, p) in self.focus_flags.iter().enumerate() {
1388 if p.lost() {
1389 let n = self.next_navigable(n);
1390 self.__focus(n, true);
1391 self.__accumulate();
1392 return true;
1393 }
1394 }
1395 if let Some(n) = self.first_navigable(0) {
1396 focus_debug!(
1397 self.log,
1398 " use first_navigable {}:{:?}",
1399 n,
1400 self.focus_flags[n].name()
1401 );
1402 self.__focus(n, true);
1403 self.__accumulate();
1404 return true;
1405 }
1406 focus_debug!(self.log, " -> no next");
1407 false
1408 }
1409
1410 pub(super) fn prev(&self) -> bool {
1412 self.__start_change(true);
1413 for (i, p) in self.focus_flags.iter().enumerate() {
1414 if p.lost() {
1415 let n = self.prev_navigable(i);
1416 self.__focus(n, true);
1417 self.__accumulate();
1418 return true;
1419 }
1420 }
1421 if let Some(n) = self.first_navigable(0) {
1422 focus_debug!(
1423 self.log,
1424 " use first_navigable {}:{:?}",
1425 n,
1426 self.focus_flags[n].name()
1427 );
1428 self.__focus(n, true);
1429 self.__accumulate();
1430 return true;
1431 }
1432 focus_debug!(self.log, " -> no prev");
1433 false
1434 }
1435
1436 pub(super) fn navigation(&self) -> Option<Navigation> {
1438 self.focus_flags
1439 .iter()
1440 .enumerate()
1441 .find(|(_, v)| v.get())
1442 .map(|(i, _)| self.navigable[i])
1443 }
1444
1445 pub(super) fn focused(&self) -> Option<FocusFlag> {
1447 self.focus_flags.iter().find(|v| v.get()).cloned()
1448 }
1449
1450 pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1452 self.focus_flags.iter().find(|v| v.lost()).cloned()
1453 }
1454
1455 pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1457 self.focus_flags.iter().find(|v| v.gained()).cloned()
1458 }
1459
1460 fn first_navigable(&self, start: usize) -> Option<usize> {
1462 focus_debug!(
1463 self.log,
1464 "first navigable, start at {}:{:?} ",
1465 start,
1466 if start < self.focus_flags.len() {
1467 self.focus_flags[start].name()
1468 } else {
1469 "beginning"
1470 }
1471 );
1472 for n in start..self.focus_flags.len() {
1473 if matches!(
1474 self.navigable[n],
1475 Navigation::Reach
1476 | Navigation::ReachLeaveBack
1477 | Navigation::ReachLeaveFront
1478 | Navigation::Regular
1479 ) {
1480 focus_debug!(self.log, " -> {}:{:?}", n, self.focus_flags[n].name());
1481 return Some(n);
1482 }
1483 }
1484 focus_debug!(self.log, " -> no first");
1485 None
1486 }
1487
1488 fn next_navigable(&self, start: usize) -> usize {
1490 focus_debug!(
1491 self.log,
1492 "next navigable after {}:{:?}",
1493 start,
1494 if start < self.focus_flags.len() {
1495 self.focus_flags[start].name()
1496 } else {
1497 "last"
1498 }
1499 );
1500
1501 let mut n = start;
1502 loop {
1503 n = if n + 1 < self.focus_flags.len() {
1504 n + 1
1505 } else {
1506 0
1507 };
1508 if matches!(
1509 self.navigable[n],
1510 Navigation::Reach
1511 | Navigation::ReachLeaveBack
1512 | Navigation::ReachLeaveFront
1513 | Navigation::Regular
1514 ) {
1515 focus_debug!(self.log, " -> {}:{:?}", n, self.focus_flags[n].name());
1516 return n;
1517 }
1518 if n == start {
1519 focus_debug!(self.log, " -> {}:end at start", n);
1520 return n;
1521 }
1522 }
1523 }
1524
1525 fn prev_navigable(&self, start: usize) -> usize {
1527 focus_debug!(
1528 self.log,
1529 "prev navigable before {}:{:?}",
1530 start,
1531 self.focus_flags[start].name()
1532 );
1533
1534 let mut n = start;
1535 loop {
1536 n = if n > 0 {
1537 n - 1
1538 } else {
1539 self.focus_flags.len() - 1
1540 };
1541 if matches!(
1542 self.navigable[n],
1543 Navigation::Reach
1544 | Navigation::ReachLeaveBack
1545 | Navigation::ReachLeaveFront
1546 | Navigation::Regular
1547 ) {
1548 focus_debug!(self.log, " -> {}:{:?}", n, self.focus_flags[n].name());
1549 return n;
1550 }
1551 if n == start {
1552 focus_debug!(self.log, " -> {}:end at start", n);
1553 return n;
1554 }
1555 }
1556 }
1557
1558 #[allow(clippy::type_complexity)]
1560 pub(super) fn clone_destruct(
1561 &self,
1562 ) -> (
1563 Vec<FocusFlag>,
1564 Vec<bool>,
1565 Vec<(Rect, u16)>,
1566 Vec<Navigation>,
1567 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1568 ) {
1569 (
1570 self.focus_flags.clone(),
1571 self.duplicate.clone(),
1572 self.areas.clone(),
1573 self.navigable.clone(),
1574 self.containers
1575 .iter()
1576 .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1577 .collect::<Vec<_>>(),
1578 )
1579 }
1580 }
1581
1582 #[cfg(test)]
1583 mod test {
1584 use crate::focus::core::FocusCore;
1585 use crate::{FocusBuilder, FocusFlag, HasFocus};
1586 use ratatui::layout::Rect;
1587
1588 #[test]
1589 fn test_change() {
1590 assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1591 assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1592
1593 assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1594 assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1595 assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1596 assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1597 assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1598
1599 assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1600 assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1601 assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1602 assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1603 assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1604
1605 assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1606 assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1607 assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1608 assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1609 assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1610
1611 assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1612 assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1613 assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1614 assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1615 assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1616 }
1617
1618 #[test]
1619 #[should_panic]
1620 fn test_double_insert() {
1621 let a = FocusFlag::named("a");
1622 let b = FocusFlag::named("b");
1623
1624 let mut fb = FocusBuilder::new(None);
1625 fb.widget(&a);
1626 fb.widget(&b);
1627 fb.widget(&a);
1628 fb.build();
1629 }
1630
1631 #[test]
1632 fn test_insert_remove() {
1633 let a = FocusFlag::named("a");
1634 let b = FocusFlag::named("b");
1635 let c = FocusFlag::named("c");
1636 let d = FocusFlag::named("d");
1637 let e = FocusFlag::named("e");
1638 let f = FocusFlag::named("f");
1639 let g = FocusFlag::named("g");
1640 let h = FocusFlag::named("h");
1641 let i = FocusFlag::named("i");
1642
1643 let mut fb = FocusBuilder::new(None);
1644 fb.widget(&a);
1645 fb.widget(&b);
1646 fb.widget(&c);
1647 let ff = fb.build();
1648 assert_eq!(ff.core.focus_flags[0], a);
1649 assert_eq!(ff.core.focus_flags[1], b);
1650 assert_eq!(ff.core.focus_flags[2], c);
1651
1652 let cc = FocusFlag::named("cc");
1653 let mut fb = FocusBuilder::new(None);
1654 fb.widget(&a);
1655 let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1656 fb.widget(&d);
1657 fb.widget(&e);
1658 fb.widget(&f);
1659 fb.end(cc_end);
1660 fb.widget(&b);
1661 fb.widget(&c);
1662 let mut ff = fb.build();
1663 assert_eq!(ff.core.focus_flags[0], a);
1664 assert_eq!(ff.core.focus_flags[1], d);
1665 assert_eq!(ff.core.focus_flags[2], e);
1666 assert_eq!(ff.core.focus_flags[3], f);
1667 assert_eq!(ff.core.focus_flags[4], b);
1668 assert_eq!(ff.core.focus_flags[5], c);
1669 assert_eq!(ff.core.containers[0].1, 1..4);
1670
1671 struct DD {
1672 dd: FocusFlag,
1673 g: FocusFlag,
1674 h: FocusFlag,
1675 i: FocusFlag,
1676 }
1677
1678 impl HasFocus for DD {
1679 fn build(&self, fb: &mut FocusBuilder) {
1680 let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1681 fb.widget(&self.g);
1682 fb.widget(&self.h);
1683 fb.widget(&self.i);
1684 fb.end(tag);
1685 }
1686
1687 fn focus(&self) -> FocusFlag {
1688 self.dd.clone()
1689 }
1690
1691 fn area(&self) -> Rect {
1692 Rect::default()
1693 }
1694 }
1695
1696 let dd = DD {
1697 dd: FocusFlag::named("dd"),
1698 g: g.clone(),
1699 h: h.clone(),
1700 i: i.clone(),
1701 };
1702 ff.replace_container(&cc, &dd);
1703 assert_eq!(ff.core.focus_flags[0], a);
1704 assert_eq!(ff.core.focus_flags[1], g);
1705 assert_eq!(ff.core.focus_flags[2], h);
1706 assert_eq!(ff.core.focus_flags[3], i);
1707 assert_eq!(ff.core.focus_flags[4], b);
1708 assert_eq!(ff.core.focus_flags[5], c);
1709 assert_eq!(ff.core.containers[0].1, 1..4);
1710 }
1711 }
1712}
1713
1714impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1715 #[inline(always)]
1716 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1717 match event {
1718 ct_event!(keycode press Tab) => {
1719 focus_debug!(
1720 self.core.log,
1721 "Tab {:?}",
1722 self.focused().map(|v| v.name().to_string())
1723 );
1724 let r = if self.next() {
1725 Outcome::Changed
1726 } else {
1727 Outcome::Continue
1728 };
1729 focus_debug!(
1730 self.core.log,
1731 " -> {:?}",
1732 self.focused().map(|v| v.name().to_string())
1733 );
1734 r
1735 }
1736 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1737 focus_debug!(
1738 self.core.log,
1739 "BackTab {:?}",
1740 self.focused().map(|v| v.name().to_string())
1741 );
1742 let r = if self.prev() {
1743 Outcome::Changed
1744 } else {
1745 Outcome::Continue
1746 };
1747 focus_debug!(
1748 self.core.log,
1749 " -> {:?}",
1750 self.focused().map(|v| v.name().to_string())
1751 );
1752 r
1753 }
1754 _ => self.handle(event, MouseOnly),
1755 }
1756 }
1757}
1758
1759impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1760 #[inline(always)]
1761 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1762 match event {
1763 ct_event!(mouse down Left for column, row) => {
1764 focus_debug!(self.core.log, "mouse down {},{}", column, row);
1765 if self.focus_at(*column, *row) {
1766 focus_debug!(
1767 self.core.log,
1768 " -> {:?}",
1769 self.focused().map(|v| v.name().to_string())
1770 );
1771 Outcome::Changed
1772 } else {
1773 self.reset_lost_gained();
1774 Outcome::Continue
1775 }
1776 }
1777 _ => {
1778 self.reset_lost_gained();
1779 Outcome::Continue
1780 }
1781 }
1782 }
1783}
1784
1785#[inline(always)]
1787pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1788 HandleEvent::handle(focus, event, Regular)
1789}