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)]
16pub struct Focus {
17 last: FocusCore,
18 core: FocusCore,
19}
20
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 pub fn enable_log(&self) {
32 self.core.log.set(true);
33 self.last.log.set(true);
34 }
35
36 pub fn disable_log(&self) {
38 self.core.log.set(false);
39 self.last.log.set(false);
40 }
41
42 #[inline]
55 pub fn focus(&self, widget_state: &'_ dyn HasFocus) {
56 focus_debug!(self.core.log, "focus {:?}", widget_state.focus().name());
57 let flag = widget_state.focus();
58 if self.core.is_widget(&flag) {
59 if let Some(n) = self.core.index_of(&flag) {
60 self.core.focus_idx(n, true);
61 } else {
62 focus_debug!(self.core.log, " => widget not found");
63 }
64 } else if self.core.is_container(&flag) {
65 self.core.first_container(&flag);
66 } else {
67 focus_debug!(self.core.log, " => not a valid widget");
68 }
69 }
70
71 #[inline]
88 pub fn by_widget_id(&self, widget_id: usize) {
89 let widget_state = self.core.find_widget_id(widget_id);
90 focus_debug!(self.core.log, "focus {:?} -> {:?}", widget_id, widget_state);
91 let Some(widget_state) = widget_state else {
92 return;
93 };
94
95 let flag = widget_state.focus();
96 if self.core.is_widget(&flag) {
97 if let Some(n) = self.core.index_of(&flag) {
98 self.core.focus_idx(n, true);
99 } else {
100 focus_debug!(self.core.log, " => widget not found");
101 }
102 } else if self.core.is_container(&flag) {
103 self.core.first_container(&flag);
104 } else {
105 focus_debug!(self.core.log, " => not a valid widget");
106 }
107 }
108
109 #[inline(always)]
118 pub fn first(&self) {
119 focus_debug!(self.core.log, "focus first");
120 self.core.first();
121 }
122
123 #[deprecated(since = "1.1.2", note = "use focus() instead")]
124 pub fn first_in(&self, container: &'_ dyn HasFocus) {
125 self.focus(container);
126 }
127
128 #[inline(always)]
133 pub fn none(&self) {
134 focus_debug!(self.core.log, "focus none");
135 self.core.none();
136 focus_debug!(self.core.log, " -> done");
137 }
138
139 #[inline(always)]
143 pub fn future(&self, widget_state: &'_ dyn HasFocus) {
144 focus_debug!(self.core.log, "future focus");
145 self.core.none();
146 widget_state.focus().set(true);
147 widget_state.focus().set_gained(true);
148 focus_debug!(self.core.log, " -> done");
149 }
150
151 #[inline(always)]
160 pub fn focus_at(&self, col: u16, row: u16) -> bool {
161 focus_debug!(self.core.log, "focus at {},{}", col, row);
162 match self.navigation() {
163 Some(Navigation::Lock) => {
164 focus_debug!(self.core.log, " -> locked");
165 false
166 }
167 _ => self.core.focus_at(col, row),
168 }
169 }
170
171 #[inline]
181 pub fn next(&self) -> bool {
182 match self.navigation() {
183 None => {
184 self.first();
185 true
186 }
187 Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
188 focus_debug!(
189 self.core.log,
190 "next after {:?}",
191 self.core
192 .focused()
193 .map(|v| v.name().to_string())
194 .unwrap_or("None".into())
195 );
196 self.core.next()
197 }
198 v => {
199 focus_debug!(
200 self.core.log,
201 "next after {:?}, but navigation says {:?}",
202 self.core
203 .focused()
204 .map(|v| v.name().to_string())
205 .unwrap_or("None".into()),
206 v
207 );
208 false
209 }
210 }
211 }
212
213 #[inline]
223 pub fn prev(&self) -> bool {
224 match self.navigation() {
225 None => {
226 self.first();
227 true
228 }
229 Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
230 focus_debug!(
231 self.core.log,
232 "prev before {:?}",
233 self.core
234 .focused()
235 .map(|v| v.name().to_string())
236 .unwrap_or("None".into())
237 );
238 self.core.prev()
239 }
240 v => {
241 focus_debug!(
242 self.core.log,
243 "prev before {:?}, but navigation says {:?}",
244 self.core
245 .focused()
246 .map(|v| v.name().to_string())
247 .unwrap_or("None".into()),
248 v
249 );
250 false
251 }
252 }
253 }
254
255 #[inline]
267 pub fn next_force(&self) -> bool {
268 match self.navigation() {
269 None => {
270 self.first();
271 true
272 }
273 Some(
274 Navigation::Leave
275 | Navigation::Reach
276 | Navigation::ReachLeaveFront
277 | Navigation::ReachLeaveBack
278 | Navigation::Regular,
279 ) => {
280 focus_debug!(
281 self.core.log,
282 "force next after {:?}",
283 self.core.focused().map(|v| v.name().to_string())
284 );
285 self.core.next()
286 }
287 v => {
288 focus_debug!(
289 self.core.log,
290 "force next after {:?}, but navigation says {:?}",
291 self.core.focused().map(|v| v.name().to_string()),
292 v
293 );
294 false
295 }
296 }
297 }
298
299 #[inline]
311 pub fn prev_force(&self) -> bool {
312 match self.navigation() {
313 None => {
314 self.first();
315 true
316 }
317 Some(
318 Navigation::Leave
319 | Navigation::Reach
320 | Navigation::ReachLeaveFront
321 | Navigation::ReachLeaveBack
322 | Navigation::Regular,
323 ) => {
324 focus_debug!(
325 self.core.log,
326 "force prev before {:?}",
327 self.core.focused().map(|v| v.name().to_string())
328 );
329 self.core.prev()
330 }
331 v => {
332 focus_debug!(
333 self.core.log,
334 "force prev before {:?}, but navigation says {:?}",
335 self.core.focused().map(|v| v.name().to_string()),
336 v
337 );
338 false
339 }
340 }
341 }
342
343 #[inline(always)]
348 pub fn focused(&self) -> Option<FocusFlag> {
349 self.core.focused()
350 }
351
352 #[inline(always)]
357 pub fn focused_widget_id(&self) -> Option<usize> {
358 self.core.focused().map(|v| v.id())
359 }
360
361 #[inline(always)]
363 pub fn focused_name(&self) -> Option<String> {
364 self.core.focused().map(|v| v.name().to_string())
365 }
366
367 #[inline(always)]
369 pub fn navigation(&self) -> Option<Navigation> {
370 self.core.navigation()
371 }
372
373 #[inline(always)]
378 pub fn lost_focus(&self) -> Option<FocusFlag> {
379 self.core.lost_focus()
380 }
381
382 #[inline(always)]
387 pub fn gained_focus(&self) -> Option<FocusFlag> {
388 self.core.gained_focus()
389 }
390
391 #[inline]
406 pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
407 focus_debug!(
408 self.core.log,
409 "focus no_lost {:?}",
410 widget_state.focus().name()
411 );
412 let flag = widget_state.focus();
413 if self.core.is_widget(&flag) {
414 if let Some(n) = self.core.index_of(&flag) {
415 self.core.focus_idx(n, false);
416 } else {
417 focus_debug!(self.core.log, " => widget not found");
418 }
419 } else if self.core.is_container(&flag) {
420 self.core.first_container(&flag);
421 } else {
422 focus_debug!(self.core.log, " => not a valid widget");
423 }
424 }
425
426 #[inline]
438 pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
439 focus_debug!(
440 self.core.log,
441 "expel from widget {:?}",
442 widget_state.focus().name()
443 );
444 let flag = widget_state.focus();
445 if self.core.is_widget(&flag) {
446 if self.core.index_of(&flag).is_some() {
447 if widget_state.is_focused() {
448 self.core.next();
449 if widget_state.is_focused() {
450 focus_debug!(self.core.log, " -> no other focus, cleared");
451 flag.clear();
452 } else {
453 focus_debug!(self.core.log, " -> expelled");
454 }
455 } else {
456 focus_debug!(self.core.log, " => widget not focused");
457 }
458 } else {
459 focus_debug!(self.core.log, " => widget not found");
460 }
461 } else if self.core.is_container(&flag) {
462 if flag.is_focused() {
463 self.core.expel_container(flag);
464 } else {
465 focus_debug!(self.core.log, " => container not focused");
466 }
467 } else {
468 focus_debug!(self.core.log, " => not a valid widget");
469 }
470 }
471
472 pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
480 focus_debug!(
481 self.core.log,
482 "focus remove container {:?} ",
483 container.focus().name()
484 );
485 let flag = container.focus();
486 if self.core.is_container(&flag) {
487 if let Some((cidx, _)) = self.core.container_index_of(&flag) {
488 self.core.remove_container(cidx).reset();
489 focus_debug!(self.core.log, " -> removed");
490 } else {
491 focus_debug!(self.core.log, " => container not found");
492 }
493 } else {
494 focus_debug!(self.core.log, " => no container flag");
495 }
496 }
497
498 pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
509 focus_debug!(
510 self.core.log,
511 "focus update container {:?} ",
512 container.focus().name()
513 );
514 let flag = container.focus();
515 if self.core.is_container(&flag) {
516 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
517 let removed = self.core.remove_container(cidx);
518
519 let mut b = FocusBuilder::new(Some(Focus {
520 last: Default::default(),
521 core: removed,
522 }));
523 b.widget(container);
524 let insert = b.build();
525
526 self.core.insert_container(range.start, cidx, insert.core);
527
528 focus_debug!(self.core.log, " -> updated");
529 } else {
530 focus_debug!(self.core.log, " => container not found");
531 }
532 } else {
533 focus_debug!(self.core.log, " => no container flag");
534 }
535 }
536
537 pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
551 focus_debug!(
552 self.core.log,
553 "focus replace container {:?} with {:?} ",
554 container.focus().name(),
555 new.focus().name()
556 );
557 let flag = container.focus();
558 if self.core.is_container(&flag) {
559 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
560 let removed = self.core.remove_container(cidx);
561
562 let mut b = FocusBuilder::new(Some(Focus {
563 last: Default::default(),
564 core: removed,
565 }));
566 b.widget(new);
567 let insert = b.build();
568
569 self.core.insert_container(range.start, cidx, insert.core);
570
571 focus_debug!(self.core.log, " -> replaced");
572 } else {
573 focus_debug!(self.core.log, " => container not found");
574 }
575 } else {
576 focus_debug!(self.core.log, " => no container flag");
577 }
578 }
579
580 #[inline(always)]
587 pub fn reset_lost_gained(&self) {
588 self.core.reset_lost_gained();
589 }
590
591 #[allow(clippy::type_complexity)]
593 pub fn clone_destruct(
594 &self,
595 ) -> (
596 Vec<FocusFlag>,
597 Vec<bool>,
598 Vec<(Rect, u16)>,
599 Vec<Navigation>,
600 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
601 ) {
602 self.core.clone_destruct()
603 }
604}
605
606mod core {
607 use crate::{Focus, FocusFlag, HasFocus, Navigation};
608 use fxhash::FxBuildHasher;
609 use ratatui::layout::Rect;
610 use std::cell::Cell;
611 use std::collections::HashSet;
612 use std::ops::Range;
613
614 #[derive(Debug, Default)]
616 pub struct FocusBuilder {
617 last: FocusCore,
618
619 log: Cell<bool>,
620
621 z_base: u16,
629
630 focus_ids: HashSet<usize, FxBuildHasher>,
632 focus_flags: Vec<FocusFlag>,
633 duplicate: Vec<bool>,
634 areas: Vec<(Rect, u16)>,
635 navigable: Vec<Navigation>,
636 container_ids: HashSet<usize, FxBuildHasher>,
637 containers: Vec<(Container, Range<usize>)>,
638 }
639
640 impl FocusBuilder {
641 pub fn new(last: Option<Focus>) -> FocusBuilder {
649 if let Some(mut last) = last {
650 last.last.clear();
652
653 Self {
654 last: last.core,
655 log: Default::default(),
656 z_base: 0,
657 focus_ids: last.last.focus_ids,
658 focus_flags: last.last.focus_flags,
659 duplicate: last.last.duplicate,
660 areas: last.last.areas,
661 navigable: last.last.navigable,
662 container_ids: last.last.container_ids,
663 containers: last.last.containers,
664 }
665 } else {
666 Self {
667 last: FocusCore::default(),
668 log: Default::default(),
669 z_base: Default::default(),
670 focus_ids: Default::default(),
671 focus_flags: Default::default(),
672 duplicate: Default::default(),
673 areas: Default::default(),
674 navigable: Default::default(),
675 container_ids: Default::default(),
676 containers: Default::default(),
677 }
678 }
679 }
680
681 pub fn build_for(container: &dyn HasFocus) -> Focus {
694 let mut b = FocusBuilder::new(None);
695 b.widget(container);
696 b.build()
697 }
698
699 pub fn rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
706 let mut b = FocusBuilder::new(old);
707 b.widget(container);
708 b.build()
709 }
710
711 pub fn enable_log(&self) {
713 self.log.set(true);
714 }
715
716 pub fn disable_log(&self) {
718 self.log.set(false);
719 }
720
721 pub fn widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
723 widget.build(self);
724 self
725 }
726
727 #[allow(clippy::collapsible_else_if)]
736 pub fn widget_navigate(
737 &mut self,
738 widget: &dyn HasFocus,
739 navigation: Navigation,
740 ) -> &mut Self {
741 widget.build(self);
742
743 let widget_flag = widget.focus();
744 if let Some(idx) = self.focus_flags.iter().position(|v| *v == widget_flag) {
746 focus_debug!(
747 self.log,
748 "override navigation for {:?} with {:?}",
749 widget_flag,
750 navigation
751 );
752
753 self.navigable[idx] = navigation;
754 } else {
755 if self.container_ids.contains(&widget_flag.widget_id()) {
756 focus_debug!(
757 self.log,
758 "FAIL to override navigation for {:?}. This is a container.",
759 widget_flag,
760 );
761 } else {
762 focus_debug!(
763 self.log,
764 "FAIL to override navigation for {:?}. Widget doesn't use this focus-flag",
765 widget_flag,
766 );
767 }
768 }
769
770 self
771 }
772
773 #[inline]
775 pub fn widgets<const N: usize>(&mut self, widgets: [&dyn HasFocus; N]) -> &mut Self {
776 for widget in widgets {
777 widget.build(self);
778 }
779 self
780 }
781
782 #[must_use]
795 pub fn start(&mut self, container: &dyn HasFocus) -> FocusFlag {
796 self.start_with_flags(container.focus(), container.area(), container.area_z())
797 }
798
799 pub fn end(&mut self, tag: FocusFlag) {
801 focus_debug!(self.log, "end container {:?}", tag);
802 assert!(self.container_ids.contains(&tag.widget_id()));
803
804 for (c, r) in self.containers.iter_mut().rev() {
805 if c.container_flag != tag {
806 if !c.complete {
807 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
808 }
809 } else {
810 r.end = self.focus_flags.len();
811 c.complete = true;
812
813 focus_debug!(self.log, "container range {:?}", r);
814
815 self.z_base -= c.delta_z;
816
817 break;
818 }
819 }
820 }
821
822 pub fn leaf_widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
834 self.widget_with_flags(
835 widget.focus(),
836 widget.area(),
837 widget.area_z(),
838 widget.navigable(),
839 );
840 self
841 }
842
843 pub fn widget_with_flags(
856 &mut self,
857 focus: FocusFlag,
858 area: Rect,
859 area_z: u16,
860 navigable: Navigation,
861 ) {
862 let duplicate = self.focus_ids.contains(&focus.widget_id());
863
864 if duplicate {
867 assert!(matches!(navigable, Navigation::Mouse | Navigation::None))
868 }
869
870 focus_debug!(self.log, "widget {:?}", focus);
871
872 self.focus_ids.insert(focus.widget_id());
873 self.focus_flags.push(focus);
874 self.duplicate.push(duplicate);
875 self.areas.push((area, self.z_base + area_z));
876 self.navigable.push(navigable);
877 }
878
879 #[must_use]
888 pub fn start_with_flags(
889 &mut self,
890 container_flag: FocusFlag,
891 area: Rect,
892 area_z: u16,
893 ) -> FocusFlag {
894 focus_debug!(self.log, "start container {:?}", container_flag);
895
896 assert!(!self.container_ids.contains(&container_flag.widget_id()));
898
899 self.z_base += area_z;
900
901 let len = self.focus_flags.len();
902 self.container_ids.insert(container_flag.widget_id());
903 self.containers.push((
904 Container {
905 container_flag: container_flag.clone(),
906 area: (area, self.z_base),
907 delta_z: area_z,
908 complete: false,
909 },
910 len..len,
911 ));
912
913 container_flag
914 }
915
916 pub fn build(mut self) -> Focus {
922 for v in &self.last.focus_flags {
924 if !self.focus_ids.contains(&v.widget_id()) {
925 v.clear();
926 }
927 }
928 for (v, _) in &self.last.containers {
929 let have_container = self
930 .containers
931 .iter()
932 .any(|(c, _)| v.container_flag == c.container_flag);
933 if !have_container {
934 v.container_flag.clear();
935 }
936 }
937 self.last.clear();
938
939 for (c, _) in self.containers.iter_mut().rev() {
941 if !c.complete {
942 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
943 }
944 }
945
946 let log = self.last.log.get();
947
948 Focus {
949 last: self.last,
950 core: FocusCore {
951 log: Cell::new(log),
952 focus_ids: self.focus_ids,
953 focus_flags: self.focus_flags,
954 duplicate: self.duplicate,
955 areas: self.areas,
956 navigable: self.navigable,
957 container_ids: self.container_ids,
958 containers: self.containers,
959 },
960 }
961 }
962 }
963
964 #[derive(Debug, Clone)]
966 struct Container {
967 container_flag: FocusFlag,
971 area: (Rect, u16),
974 delta_z: u16,
976 complete: bool,
978 }
979
980 #[derive(Debug, Default, Clone)]
982 pub(super) struct FocusCore {
983 pub(super) log: Cell<bool>,
985
986 focus_ids: HashSet<usize, FxBuildHasher>,
988 focus_flags: Vec<FocusFlag>,
990 duplicate: Vec<bool>,
993 areas: Vec<(Rect, u16)>,
996 navigable: Vec<Navigation>,
998 container_ids: HashSet<usize, FxBuildHasher>,
1000 containers: Vec<(Container, Range<usize>)>,
1005 }
1006
1007 impl FocusCore {
1008 pub(super) fn clear(&mut self) {
1010 self.focus_ids.clear();
1011 self.focus_flags.clear();
1012 self.duplicate.clear();
1013 self.areas.clear();
1014 self.navigable.clear();
1015 self.container_ids.clear();
1016 self.containers.clear();
1017 }
1018
1019 pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
1021 self.focus_flags
1022 .iter()
1023 .find(|v| widget_id == v.widget_id())
1024 .cloned()
1025 }
1026
1027 pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
1029 self.focus_ids.contains(&focus_flag.widget_id())
1030 }
1031
1032 pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
1034 self.focus_flags
1035 .iter()
1036 .enumerate()
1037 .find(|(_, f)| *f == focus_flag)
1038 .map(|(idx, _)| idx)
1039 }
1040
1041 pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
1043 self.container_ids.contains(&focus_flag.widget_id())
1044 }
1045
1046 pub(super) fn container_index_of(
1048 &self,
1049 container_flag: &FocusFlag,
1050 ) -> Option<(usize, Range<usize>)> {
1051 self.containers
1052 .iter()
1053 .enumerate()
1054 .find(|(_, (c, _))| &c.container_flag == container_flag)
1055 .map(|(idx, (_, range))| (idx, range.clone()))
1056 }
1057
1058 pub(super) fn insert_container(
1063 &mut self,
1064 idx: usize,
1065 cidx: usize,
1066 mut container: FocusCore,
1067 ) {
1068 for c in &self.focus_flags {
1069 for d in &container.focus_flags {
1070 assert_ne!(c, d);
1071 }
1072 }
1073
1074 let start = idx;
1076 let end = idx + container.focus_flags.len();
1077
1078 self.focus_ids.extend(container.focus_ids.iter());
1079 self.focus_flags
1080 .splice(idx..idx, container.focus_flags.drain(..));
1081 self.duplicate
1082 .splice(idx..idx, container.duplicate.drain(..));
1083 self.areas.splice(idx..idx, container.areas.drain(..));
1084 self.navigable
1085 .splice(idx..idx, container.navigable.drain(..));
1086
1087 for (_, r) in &mut self.containers {
1089 *r = Self::expand(start..end, r.clone());
1090 }
1091 self.containers.splice(
1093 cidx..cidx,
1094 container
1095 .containers
1096 .drain(..)
1097 .map(|(c, r)| (c, Self::shift(start, r))),
1098 );
1099 self.container_ids.extend(container.container_ids.iter());
1100 }
1101
1102 pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1105 let crange = self.containers[cidx].1.clone();
1106
1107 let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1109 let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1110 for f in focus_flags.iter() {
1111 self.focus_ids.remove(&f.widget_id());
1112 focus_ids.insert(f.widget_id());
1113 }
1114 let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1115 let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1116 let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1117 let sub_containers = self
1118 .containers
1119 .iter()
1120 .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1121 .cloned()
1122 .collect::<Vec<_>>();
1123 self.containers
1125 .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1126 let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1127 for (sc, _) in sub_containers.iter() {
1128 self.container_ids.remove(&sc.container_flag.widget_id());
1129 sub_container_ids.insert(sc.container_flag.widget_id());
1130 }
1131
1132 for (_, r) in &mut self.containers {
1134 *r = Self::shrink(crange.start..crange.end, r.clone());
1135 }
1136
1137 FocusCore {
1138 log: Cell::new(false),
1139 focus_ids,
1140 focus_flags,
1141 duplicate,
1142 areas,
1143 navigable,
1144 container_ids: sub_container_ids,
1145 containers: sub_containers,
1146 }
1147 }
1148
1149 fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1151 range.start + n..range.end + n
1152 }
1153
1154 fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1156 let len = insert.end - insert.start;
1157
1158 if range.start >= insert.start {
1159 range.start += len;
1160 }
1161 if range.end > insert.start {
1162 range.end += len;
1163 }
1164 range
1165 }
1166
1167 fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1169 let len = remove.end - remove.start;
1170
1171 if range.start < remove.start {
1172 } else if range.start >= remove.start && range.start <= remove.end {
1174 range.start = remove.start;
1175 } else {
1176 range.start -= len;
1177 }
1178
1179 if range.end < remove.start {
1180 } else if range.end >= remove.start && range.end <= remove.end {
1182 range.end = remove.start;
1183 } else {
1184 range.end -= len;
1185 }
1186
1187 range
1188 }
1189
1190 fn __start_change(&self, set_lost: bool) {
1193 for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1194 if *duplicate {
1195 continue;
1197 }
1198 if set_lost {
1199 f.set_lost(f.get());
1200 } else {
1201 f.set_lost(false);
1202 }
1203 f.set_gained(false);
1204 f.set(false);
1205 }
1206 }
1207
1208 fn __focus(&self, n: usize, set_lost: bool) -> bool {
1211 if let Some(f) = self.focus_flags.get(n) {
1212 focus_debug!(self.log, " -> focus {}:{:?}", n, f.name());
1213 f.set(true);
1214 if set_lost {
1215 if f.lost() {
1216 f.set_lost(false);
1219 f.set_gained(false);
1220 false
1221 } else {
1222 f.set_gained(true);
1223 true
1224 }
1225 } else {
1226 false
1227 }
1228 } else {
1229 false
1230 }
1231 }
1232
1233 fn __accumulate(&self) {
1235 for (f, r) in &self.containers {
1236 let mut any_gained = false;
1237 let mut any_lost = false;
1238 let mut any_focused = false;
1239
1240 for idx in r.clone() {
1241 any_gained |= self.focus_flags[idx].gained();
1242 any_lost |= self.focus_flags[idx].lost();
1243 any_focused |= self.focus_flags[idx].get();
1244 }
1245
1246 f.container_flag.set(any_focused);
1247 f.container_flag.set_lost(any_lost && !any_gained);
1248 f.container_flag.set_gained(any_gained && !any_lost);
1249 }
1250 }
1251
1252 pub(super) fn reset(&self) {
1254 for f in self.focus_flags.iter() {
1255 f.set(false);
1256 f.set_lost(false);
1257 f.set_gained(false);
1258 }
1259 for (f, _) in self.containers.iter() {
1260 f.container_flag.set(false);
1261 f.container_flag.set_gained(false);
1262 f.container_flag.set_lost(false);
1263 }
1264 }
1265
1266 pub(super) fn reset_lost_gained(&self) {
1268 for f in self.focus_flags.iter() {
1269 f.set_lost(false);
1270 f.set_gained(false);
1271 }
1272 for (f, _) in self.containers.iter() {
1273 f.container_flag.set_gained(false);
1274 f.container_flag.set_lost(false);
1275 }
1276 }
1277
1278 pub(super) fn first(&self) {
1280 if let Some(n) = self.first_navigable(0) {
1281 self.__start_change(true);
1282 self.__focus(n, true);
1283 self.__accumulate();
1284 } else {
1285 focus_debug!(self.log, " -> no navigable widget");
1286 }
1287 }
1288
1289 pub(super) fn none(&self) {
1291 self.__start_change(true);
1292 self.__accumulate();
1293 }
1294
1295 pub(super) fn first_container(&self, container: &FocusFlag) {
1297 if let Some((_idx, range)) = self.container_index_of(container) {
1298 if let Some(n) = self.first_navigable(range.start) {
1299 if n < range.end {
1300 self.__start_change(true);
1301 self.__focus(n, true);
1302 self.__accumulate();
1303 } else {
1304 focus_debug!(self.log, " -> no navigable widget for container");
1305 }
1306 } else {
1307 focus_debug!(self.log, " -> no navigable widget");
1308 }
1309 } else {
1310 focus_debug!(self.log, " => container not found");
1311 }
1312 }
1313
1314 pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1316 self.__start_change(set_lost);
1317 self.__focus(n, set_lost);
1318 self.__accumulate();
1319 }
1320
1321 pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1325 let pos = (col, row).into();
1326
1327 enum ZOrder {
1328 Widget(usize),
1329 Container(usize),
1330 }
1331
1332 let mut z_order: Option<(ZOrder, u16)> = None;
1334 for (idx, (sub, _)) in self.containers.iter().enumerate() {
1337 if sub.area.0.contains(pos) {
1338 focus_debug!(
1339 self.log,
1340 " container area-match {:?}",
1341 sub.container_flag.name()
1342 );
1343
1344 z_order = if let Some(zz) = z_order {
1345 if zz.1 <= sub.area.1 {
1346 Some((ZOrder::Container(idx), sub.area.1))
1347 } else {
1348 Some(zz)
1349 }
1350 } else {
1351 Some((ZOrder::Container(idx), sub.area.1))
1352 };
1353 }
1354 }
1355 for (idx, area) in self.areas.iter().enumerate() {
1357 if area.0.contains(pos) {
1358 focus_debug!(
1359 self.log,
1360 " area-match {:?}",
1361 self.focus_flags[idx].name()
1362 );
1363
1364 z_order = if let Some(zz) = z_order {
1365 if zz.1 <= area.1 {
1366 Some((ZOrder::Widget(idx), area.1))
1367 } else {
1368 Some(zz)
1369 }
1370 } else {
1371 Some((ZOrder::Widget(idx), area.1))
1372 };
1373 }
1374 }
1375
1376 if let Some((idx, _)) = z_order {
1378 match idx {
1379 ZOrder::Widget(idx) => {
1380 if self.navigable[idx] != Navigation::None {
1381 self.__start_change(true);
1382 let r = self.__focus(idx, true);
1383 self.__accumulate();
1384 return r;
1385 } else {
1386 focus_debug!(
1387 self.log,
1388 " -> not mouse reachable {:?}",
1389 self.focus_flags[idx].name()
1390 );
1391 return false;
1392 }
1393 }
1394 ZOrder::Container(idx) => {
1395 let range = &self.containers[idx].1;
1396 if let Some(n) = self.first_navigable(range.start) {
1397 self.__start_change(true);
1398 let r = self.__focus(n, true);
1399 self.__accumulate();
1400 return r;
1401 }
1402 }
1403 }
1404 }
1405
1406 focus_debug!(self.log, " -> no widget at pos");
1408
1409 false
1410 }
1411
1412 pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1414 if let Some((_idx, range)) = self.container_index_of(&flag) {
1415 self.__start_change(true);
1416 let n = self.next_navigable(range.end);
1417 self.__focus(n, true);
1418 self.__accumulate();
1419
1420 if flag.is_focused() {
1422 focus_debug!(self.log, " -> focus not usable. cleared");
1423 self.none();
1424 } else {
1425 focus_debug!(self.log, " -> expelled.");
1426 }
1427 true
1428 } else {
1429 focus_debug!(self.log, " => container not found");
1430 false
1431 }
1432 }
1433
1434 pub(super) fn next(&self) -> bool {
1436 self.__start_change(true);
1437 for (n, p) in self.focus_flags.iter().enumerate() {
1438 if p.lost() {
1439 let n = self.next_navigable(n);
1440 self.__focus(n, true);
1441 self.__accumulate();
1442 return true;
1443 }
1444 }
1445 if let Some(n) = self.first_navigable(0) {
1446 focus_debug!(
1447 self.log,
1448 " use first_navigable {}:{:?}",
1449 n,
1450 self.focus_flags[n].name()
1451 );
1452 self.__focus(n, true);
1453 self.__accumulate();
1454 return true;
1455 }
1456 focus_debug!(self.log, " -> no next");
1457 false
1458 }
1459
1460 pub(super) fn prev(&self) -> bool {
1462 self.__start_change(true);
1463 for (i, p) in self.focus_flags.iter().enumerate() {
1464 if p.lost() {
1465 let n = self.prev_navigable(i);
1466 self.__focus(n, true);
1467 self.__accumulate();
1468 return true;
1469 }
1470 }
1471 if let Some(n) = self.first_navigable(0) {
1472 focus_debug!(
1473 self.log,
1474 " use first_navigable {}:{:?}",
1475 n,
1476 self.focus_flags[n].name()
1477 );
1478 self.__focus(n, true);
1479 self.__accumulate();
1480 return true;
1481 }
1482 focus_debug!(self.log, " -> no prev");
1483 false
1484 }
1485
1486 pub(super) fn navigation(&self) -> Option<Navigation> {
1488 self.focus_flags
1489 .iter()
1490 .enumerate()
1491 .find(|(_, v)| v.get())
1492 .map(|(i, _)| self.navigable[i])
1493 }
1494
1495 pub(super) fn focused(&self) -> Option<FocusFlag> {
1497 self.focus_flags.iter().find(|v| v.get()).cloned()
1498 }
1499
1500 pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1502 self.focus_flags.iter().find(|v| v.lost()).cloned()
1503 }
1504
1505 pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1507 self.focus_flags.iter().find(|v| v.gained()).cloned()
1508 }
1509
1510 fn first_navigable(&self, start: usize) -> Option<usize> {
1512 focus_debug!(
1513 self.log,
1514 "first navigable, start at {}:{:?} ",
1515 start,
1516 if start < self.focus_flags.len() {
1517 self.focus_flags[start].name()
1518 } else {
1519 "beginning"
1520 }
1521 );
1522 for n in start..self.focus_flags.len() {
1523 if matches!(
1524 self.navigable[n],
1525 Navigation::Reach
1526 | Navigation::ReachLeaveBack
1527 | Navigation::ReachLeaveFront
1528 | Navigation::Regular
1529 ) {
1530 focus_debug!(self.log, " -> {}:{:?}", n, self.focus_flags[n].name());
1531 return Some(n);
1532 }
1533 }
1534 focus_debug!(self.log, " -> no first");
1535 None
1536 }
1537
1538 fn next_navigable(&self, start: usize) -> usize {
1540 focus_debug!(
1541 self.log,
1542 "next navigable after {}:{:?}",
1543 start,
1544 if start < self.focus_flags.len() {
1545 self.focus_flags[start].name()
1546 } else {
1547 "last"
1548 }
1549 );
1550
1551 let mut n = start;
1552 loop {
1553 n = if n + 1 < self.focus_flags.len() {
1554 n + 1
1555 } else {
1556 0
1557 };
1558 if matches!(
1559 self.navigable[n],
1560 Navigation::Reach
1561 | Navigation::ReachLeaveBack
1562 | Navigation::ReachLeaveFront
1563 | Navigation::Regular
1564 ) {
1565 focus_debug!(self.log, " -> {}:{:?}", n, self.focus_flags[n].name());
1566 return n;
1567 }
1568 if n == start {
1569 focus_debug!(self.log, " -> {}:end at start", n);
1570 return n;
1571 }
1572 }
1573 }
1574
1575 fn prev_navigable(&self, start: usize) -> usize {
1577 focus_debug!(
1578 self.log,
1579 "prev navigable before {}:{:?}",
1580 start,
1581 self.focus_flags[start].name()
1582 );
1583
1584 let mut n = start;
1585 loop {
1586 n = if n > 0 {
1587 n - 1
1588 } else {
1589 self.focus_flags.len() - 1
1590 };
1591 if matches!(
1592 self.navigable[n],
1593 Navigation::Reach
1594 | Navigation::ReachLeaveBack
1595 | Navigation::ReachLeaveFront
1596 | Navigation::Regular
1597 ) {
1598 focus_debug!(self.log, " -> {}:{:?}", n, self.focus_flags[n].name());
1599 return n;
1600 }
1601 if n == start {
1602 focus_debug!(self.log, " -> {}:end at start", n);
1603 return n;
1604 }
1605 }
1606 }
1607
1608 #[allow(clippy::type_complexity)]
1610 pub(super) fn clone_destruct(
1611 &self,
1612 ) -> (
1613 Vec<FocusFlag>,
1614 Vec<bool>,
1615 Vec<(Rect, u16)>,
1616 Vec<Navigation>,
1617 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1618 ) {
1619 (
1620 self.focus_flags.clone(),
1621 self.duplicate.clone(),
1622 self.areas.clone(),
1623 self.navigable.clone(),
1624 self.containers
1625 .iter()
1626 .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1627 .collect::<Vec<_>>(),
1628 )
1629 }
1630 }
1631
1632 #[cfg(test)]
1633 mod test {
1634 use crate::focus::core::FocusCore;
1635 use crate::{FocusBuilder, FocusFlag, HasFocus};
1636 use ratatui::layout::Rect;
1637
1638 #[test]
1639 fn test_change() {
1640 assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1641 assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1642
1643 assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1644 assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1645 assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1646 assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1647 assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1648
1649 assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1650 assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1651 assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1652 assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1653 assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1654
1655 assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1656 assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1657 assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1658 assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1659 assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1660
1661 assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1662 assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1663 assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1664 assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1665 assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1666 }
1667
1668 #[test]
1669 #[should_panic]
1670 fn test_double_insert() {
1671 let a = FocusFlag::named("a");
1672 let b = FocusFlag::named("b");
1673
1674 let mut fb = FocusBuilder::new(None);
1675 fb.widget(&a);
1676 fb.widget(&b);
1677 fb.widget(&a);
1678 fb.build();
1679 }
1680
1681 #[test]
1682 fn test_insert_remove() {
1683 let a = FocusFlag::named("a");
1684 let b = FocusFlag::named("b");
1685 let c = FocusFlag::named("c");
1686 let d = FocusFlag::named("d");
1687 let e = FocusFlag::named("e");
1688 let f = FocusFlag::named("f");
1689 let g = FocusFlag::named("g");
1690 let h = FocusFlag::named("h");
1691 let i = FocusFlag::named("i");
1692
1693 let mut fb = FocusBuilder::new(None);
1694 fb.widget(&a);
1695 fb.widget(&b);
1696 fb.widget(&c);
1697 let ff = fb.build();
1698 assert_eq!(ff.core.focus_flags[0], a);
1699 assert_eq!(ff.core.focus_flags[1], b);
1700 assert_eq!(ff.core.focus_flags[2], c);
1701
1702 let cc = FocusFlag::named("cc");
1703 let mut fb = FocusBuilder::new(None);
1704 fb.widget(&a);
1705 let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1706 fb.widget(&d);
1707 fb.widget(&e);
1708 fb.widget(&f);
1709 fb.end(cc_end);
1710 fb.widget(&b);
1711 fb.widget(&c);
1712 let mut ff = fb.build();
1713 assert_eq!(ff.core.focus_flags[0], a);
1714 assert_eq!(ff.core.focus_flags[1], d);
1715 assert_eq!(ff.core.focus_flags[2], e);
1716 assert_eq!(ff.core.focus_flags[3], f);
1717 assert_eq!(ff.core.focus_flags[4], b);
1718 assert_eq!(ff.core.focus_flags[5], c);
1719 assert_eq!(ff.core.containers[0].1, 1..4);
1720
1721 struct DD {
1722 dd: FocusFlag,
1723 g: FocusFlag,
1724 h: FocusFlag,
1725 i: FocusFlag,
1726 }
1727
1728 impl HasFocus for DD {
1729 fn build(&self, fb: &mut FocusBuilder) {
1730 let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1731 fb.widget(&self.g);
1732 fb.widget(&self.h);
1733 fb.widget(&self.i);
1734 fb.end(tag);
1735 }
1736
1737 fn focus(&self) -> FocusFlag {
1738 self.dd.clone()
1739 }
1740
1741 fn area(&self) -> Rect {
1742 Rect::default()
1743 }
1744 }
1745
1746 let dd = DD {
1747 dd: FocusFlag::named("dd"),
1748 g: g.clone(),
1749 h: h.clone(),
1750 i: i.clone(),
1751 };
1752 ff.replace_container(&cc, &dd);
1753 assert_eq!(ff.core.focus_flags[0], a);
1754 assert_eq!(ff.core.focus_flags[1], g);
1755 assert_eq!(ff.core.focus_flags[2], h);
1756 assert_eq!(ff.core.focus_flags[3], i);
1757 assert_eq!(ff.core.focus_flags[4], b);
1758 assert_eq!(ff.core.focus_flags[5], c);
1759 assert_eq!(ff.core.containers[0].1, 1..4);
1760 }
1761 }
1762}
1763
1764impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1765 #[inline(always)]
1766 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1767 match event {
1768 ct_event!(keycode press Tab) => {
1769 focus_debug!(
1770 self.core.log,
1771 "Tab {:?}",
1772 self.focused().map(|v| v.name().to_string())
1773 );
1774 let r = if self.next() {
1775 Outcome::Changed
1776 } else {
1777 Outcome::Continue
1778 };
1779 focus_debug!(
1780 self.core.log,
1781 " -> {:?}",
1782 self.focused().map(|v| v.name().to_string())
1783 );
1784 r
1785 }
1786 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1787 focus_debug!(
1788 self.core.log,
1789 "BackTab {:?}",
1790 self.focused().map(|v| v.name().to_string())
1791 );
1792 let r = if self.prev() {
1793 Outcome::Changed
1794 } else {
1795 Outcome::Continue
1796 };
1797 focus_debug!(
1798 self.core.log,
1799 " -> {:?}",
1800 self.focused().map(|v| v.name().to_string())
1801 );
1802 r
1803 }
1804 _ => self.handle(event, MouseOnly),
1805 }
1806 }
1807}
1808
1809impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1810 #[inline(always)]
1811 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1812 match event {
1813 ct_event!(mouse down Left for column, row) => {
1814 focus_debug!(self.core.log, "mouse down {},{}", column, row);
1815 if self.focus_at(*column, *row) {
1816 focus_debug!(
1817 self.core.log,
1818 " -> {:?}",
1819 self.focused().map(|v| v.name().to_string())
1820 );
1821 Outcome::Changed
1822 } else {
1823 self.reset_lost_gained();
1824 Outcome::Continue
1825 }
1826 }
1827 _ => {
1828 self.reset_lost_gained();
1829 Outcome::Continue
1830 }
1831 }
1832 }
1833}
1834
1835#[inline(always)]
1837pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1838 HandleEvent::handle(focus, event, Regular)
1839}