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 ($core:expr, $($arg:tt)+) => {
23 if $core.log.get() {
24 log::log!(log::Level::Debug, $($arg)+);
25 }
26 }
27}
28
29macro_rules! focus_fail {
30 ($core:expr, $($arg:tt)+) => {
31 if $core.log.get() {
32 log::log!(log::Level::Debug, $($arg)+);
33 }
34 if $core.insta_panic.get() {
35 panic!($($arg)+)
36 }
37 }
38}
39
40impl Focus {
41 pub fn enable_log(&self) {
43 self.core.log.set(true);
44 self.last.log.set(true);
45 }
46
47 pub fn disable_log(&self) {
49 self.core.log.set(false);
50 self.last.log.set(false);
51 }
52
53 pub fn enable_panic(&self) {
56 self.core.insta_panic.set(true);
57 self.last.insta_panic.set(true);
58 }
59
60 pub fn disable_panic(&self) {
62 self.core.insta_panic.set(false);
63 self.last.insta_panic.set(false);
64 }
65
66 #[inline]
79 pub fn focus(&self, widget_state: &'_ dyn HasFocus) {
80 focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
81 let flag = widget_state.focus();
82 if self.core.is_widget(&flag) {
83 if let Some(n) = self.core.index_of(&flag) {
84 self.core.focus_idx(n, true);
85 } else {
86 panic!(" => invalid widget?");
87 }
88 } else if self.core.is_container(&flag) {
89 self.core.first_container(&flag);
90 } else {
91 focus_fail!(self.core, " => not a valid widget");
92 }
93 }
94
95 #[inline]
112 pub fn by_widget_id(&self, widget_id: usize) {
113 let widget_state = self.core.find_widget_id(widget_id);
114 focus_debug!(self.core, "focus {:?} -> {:?}", widget_id, widget_state);
115 let Some(widget_state) = widget_state else {
116 return;
117 };
118
119 let flag = widget_state.focus();
120 if self.core.is_widget(&flag) {
121 if let Some(n) = self.core.index_of(&flag) {
122 self.core.focus_idx(n, true);
123 } else {
124 panic!(" => invalid widget");
125 }
126 } else if self.core.is_container(&flag) {
127 self.core.first_container(&flag);
128 } else {
129 focus_fail!(self.core, " => not a valid widget");
130 }
131 }
132
133 #[inline(always)]
142 pub fn first(&self) {
143 focus_debug!(self.core, "focus first");
144 self.core.first();
145 }
146
147 #[deprecated(since = "1.1.2", note = "use focus() instead")]
148 pub fn first_in(&self, container: &'_ dyn HasFocus) {
149 self.focus(container);
150 }
151
152 #[inline(always)]
157 pub fn none(&self) {
158 focus_debug!(self.core, "focus none");
159 self.core.none();
160 focus_debug!(self.core, " -> done");
161 }
162
163 #[inline(always)]
175 pub fn future(&self, widget_state: &'_ dyn HasFocus) {
176 focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
177 let flag = widget_state.focus();
178 if self.core.is_widget(&flag) {
179 if let Some(n) = self.core.index_of(&flag) {
180 self.core.focus_idx(n, true);
181 } else {
182 panic!(" => invalid widget");
183 }
184 } else if self.core.is_container(&flag) {
185 self.core.first_container(&flag);
186 } else {
187 focus_debug!(self.core, "future focus");
188 self.core.none();
189 widget_state.focus().set(true);
190 widget_state.focus().set_gained(true);
191 focus_debug!(self.core, " -> done");
192 }
193 }
194
195 #[inline(always)]
204 pub fn focus_at(&self, col: u16, row: u16) -> bool {
205 focus_debug!(self.core, "focus at {},{}", col, row);
206 match self.navigation() {
207 Some(Navigation::Lock) => {
208 focus_debug!(self.core, " -> locked");
209 false
210 }
211 _ => self.core.focus_at(col, row),
212 }
213 }
214
215 #[inline]
225 pub fn next(&self) -> bool {
226 match self.navigation() {
227 None => {
228 self.first();
229 true
230 }
231 Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
232 focus_debug!(
233 self.core,
234 "next after {:?}",
235 self.core
236 .focused()
237 .map(|v| v.name().to_string())
238 .unwrap_or("None".into())
239 );
240 self.core.next()
241 }
242 v => {
243 focus_debug!(
244 self.core,
245 "next after {:?}, but navigation says {:?}",
246 self.core
247 .focused()
248 .map(|v| v.name().to_string())
249 .unwrap_or("None".into()),
250 v
251 );
252 false
253 }
254 }
255 }
256
257 #[inline]
267 pub fn prev(&self) -> bool {
268 match self.navigation() {
269 None => {
270 self.first();
271 true
272 }
273 Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
274 focus_debug!(
275 self.core,
276 "prev before {:?}",
277 self.core
278 .focused()
279 .map(|v| v.name().to_string())
280 .unwrap_or("None".into())
281 );
282 self.core.prev()
283 }
284 v => {
285 focus_debug!(
286 self.core,
287 "prev before {:?}, but navigation says {:?}",
288 self.core
289 .focused()
290 .map(|v| v.name().to_string())
291 .unwrap_or("None".into()),
292 v
293 );
294 false
295 }
296 }
297 }
298
299 #[inline]
311 pub fn next_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,
326 "force next after {:?}",
327 self.core.focused().map(|v| v.name().to_string())
328 );
329 self.core.next()
330 }
331 v => {
332 focus_debug!(
333 self.core,
334 "force next after {:?}, but navigation says {:?}",
335 self.core.focused().map(|v| v.name().to_string()),
336 v
337 );
338 false
339 }
340 }
341 }
342
343 #[inline]
355 pub fn prev_force(&self) -> bool {
356 match self.navigation() {
357 None => {
358 self.first();
359 true
360 }
361 Some(
362 Navigation::Leave
363 | Navigation::Reach
364 | Navigation::ReachLeaveFront
365 | Navigation::ReachLeaveBack
366 | Navigation::Regular,
367 ) => {
368 focus_debug!(
369 self.core,
370 "force prev before {:?}",
371 self.core.focused().map(|v| v.name().to_string())
372 );
373 self.core.prev()
374 }
375 v => {
376 focus_debug!(
377 self.core,
378 "force prev before {:?}, but navigation says {:?}",
379 self.core.focused().map(|v| v.name().to_string()),
380 v
381 );
382 false
383 }
384 }
385 }
386
387 #[inline(always)]
389 pub fn is_valid_widget(&self, widget_state: &'_ dyn HasFocus) -> bool {
390 self.core.is_widget(&widget_state.focus())
391 }
392
393 #[inline(always)]
395 pub fn is_valid_container(&self, widget_state: &'_ dyn HasFocus) -> bool {
396 self.core.is_container(&widget_state.focus())
397 }
398
399 #[inline(always)]
404 pub fn focused(&self) -> Option<FocusFlag> {
405 self.core.focused()
406 }
407
408 #[inline(always)]
413 pub fn focused_widget_id(&self) -> Option<usize> {
414 self.core.focused().map(|v| v.id())
415 }
416
417 #[inline(always)]
419 pub fn focused_name(&self) -> Option<String> {
420 self.core.focused().map(|v| v.name().to_string())
421 }
422
423 #[inline(always)]
425 pub fn navigation(&self) -> Option<Navigation> {
426 self.core.navigation()
427 }
428
429 #[inline(always)]
434 pub fn lost_focus(&self) -> Option<FocusFlag> {
435 self.core.lost_focus()
436 }
437
438 #[inline(always)]
443 pub fn gained_focus(&self) -> Option<FocusFlag> {
444 self.core.gained_focus()
445 }
446
447 #[inline]
462 pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
463 focus_debug!(self.core, "focus no_lost {:?}", widget_state.focus().name());
464 let flag = widget_state.focus();
465 if self.core.is_widget(&flag) {
466 if let Some(n) = self.core.index_of(&flag) {
467 self.core.focus_idx(n, false);
468 } else {
469 panic!(" => invalid widget");
470 }
471 } else if self.core.is_container(&flag) {
472 self.core.first_container(&flag);
473 } else {
474 focus_fail!(self.core, " => not a valid widget");
475 }
476 }
477
478 #[inline]
490 pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
491 focus_debug!(
492 self.core,
493 "expel from widget {:?}",
494 widget_state.focus().name()
495 );
496 let flag = widget_state.focus();
497 if self.core.is_widget(&flag) {
498 if self.core.index_of(&flag).is_some() {
499 if widget_state.is_focused() {
500 self.core.next();
501 if widget_state.is_focused() {
502 focus_debug!(self.core, " -> no other focus, cleared");
503 flag.clear();
504 } else {
505 focus_debug!(self.core, " -> expelled");
506 }
507 } else {
508 focus_debug!(self.core, " => widget not focused");
509 }
510 } else {
511 panic!(" => invalid widget");
512 }
513 } else if self.core.is_container(&flag) {
514 if flag.is_focused() {
515 self.core.expel_container(flag);
516 } else {
517 focus_debug!(self.core, " => container not focused");
518 }
519 } else {
520 focus_fail!(self.core, " => not a valid widget");
521 }
522 }
523
524 pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
532 focus_debug!(
533 self.core,
534 "focus remove container {:?} ",
535 container.focus().name()
536 );
537 let flag = container.focus();
538 if self.core.is_container(&flag) {
539 if let Some((cidx, _)) = self.core.container_index_of(&flag) {
540 self.core.remove_container(cidx).reset();
541 focus_debug!(self.core, " -> removed");
542 } else {
543 panic!(" => invalid container?");
544 }
545 } else {
546 focus_fail!(self.core, " => no container flag");
547 }
548 }
549
550 pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
561 focus_debug!(
562 self.core,
563 "focus update container {:?} ",
564 container.focus().name()
565 );
566 let flag = container.focus();
567 if self.core.is_container(&flag) {
568 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
569 let removed = self.core.remove_container(cidx);
570
571 let mut b = FocusBuilder::new(Some(Focus {
572 last: Default::default(),
573 core: removed,
574 }));
575 b.widget(container);
576 let insert = b.build();
577
578 self.core.insert_container(range.start, cidx, insert.core);
579
580 focus_debug!(self.core, " -> updated");
581 } else {
582 panic!(" => invalid container?");
583 }
584 } else {
585 focus_fail!(self.core, " => no container flag");
586 }
587 }
588
589 pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
603 focus_debug!(
604 self.core,
605 "focus replace container {:?} with {:?} ",
606 container.focus().name(),
607 new.focus().name()
608 );
609 let flag = container.focus();
610 if self.core.is_container(&flag) {
611 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
612 let removed = self.core.remove_container(cidx);
613
614 let mut b = FocusBuilder::new(Some(Focus {
615 last: Default::default(),
616 core: removed,
617 }));
618 b.widget(new);
619 let insert = b.build();
620
621 self.core.insert_container(range.start, cidx, insert.core);
622
623 focus_debug!(self.core, " -> replaced");
624 } else {
625 panic!(" => invalid container");
626 }
627 } else {
628 focus_fail!(self.core, " => no container flag");
629 }
630 }
631
632 #[inline(always)]
639 pub fn reset_lost_gained(&self) {
640 self.core.reset_lost_gained();
641 }
642
643 #[allow(clippy::type_complexity)]
645 pub fn clone_destruct(
646 &self,
647 ) -> (
648 Vec<FocusFlag>,
649 Vec<bool>,
650 Vec<(Rect, u16)>,
651 Vec<Navigation>,
652 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
653 ) {
654 self.core.clone_destruct()
655 }
656}
657
658mod core {
659 use crate::{Focus, FocusFlag, HasFocus, Navigation};
660 use fxhash::FxBuildHasher;
661 use ratatui::layout::Rect;
662 use std::cell::Cell;
663 use std::collections::HashSet;
664 use std::ops::Range;
665
666 #[derive(Debug, Default)]
668 pub struct FocusBuilder {
669 last: FocusCore,
670
671 log: Cell<bool>,
672 insta_panic: Cell<bool>,
673
674 z_base: u16,
682
683 focus_ids: HashSet<usize, FxBuildHasher>,
685 focus_flags: Vec<FocusFlag>,
686 duplicate: Vec<bool>,
687 areas: Vec<(Rect, u16)>,
688 navigable: Vec<Navigation>,
689 container_ids: HashSet<usize, FxBuildHasher>,
690 containers: Vec<(Container, Range<usize>)>,
691 }
692
693 impl FocusBuilder {
694 pub fn new(last: Option<Focus>) -> FocusBuilder {
702 if let Some(mut last) = last {
703 last.last.clear();
705
706 Self {
707 last: last.core,
708 log: Default::default(),
709 insta_panic: Default::default(),
710 z_base: 0,
711 focus_ids: last.last.focus_ids,
712 focus_flags: last.last.focus_flags,
713 duplicate: last.last.duplicate,
714 areas: last.last.areas,
715 navigable: last.last.navigable,
716 container_ids: last.last.container_ids,
717 containers: last.last.containers,
718 }
719 } else {
720 Self {
721 last: FocusCore::default(),
722 log: Default::default(),
723 insta_panic: Default::default(),
724 z_base: Default::default(),
725 focus_ids: Default::default(),
726 focus_flags: Default::default(),
727 duplicate: Default::default(),
728 areas: Default::default(),
729 navigable: Default::default(),
730 container_ids: Default::default(),
731 containers: Default::default(),
732 }
733 }
734 }
735
736 pub fn log_build_for(container: &dyn HasFocus) -> Focus {
738 let mut b = FocusBuilder::new(None);
739 b.enable_log();
740 b.widget(container);
741 b.build()
742 }
743
744 pub fn build_for(container: &dyn HasFocus) -> Focus {
757 let mut b = FocusBuilder::new(None);
758 b.widget(container);
759 b.build()
760 }
761
762 pub fn log_rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
764 let mut b = FocusBuilder::new(old);
765 b.enable_log();
766 b.widget(container);
767 b.build()
768 }
769
770 pub fn rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
777 let mut b = FocusBuilder::new(old);
778 b.widget(container);
779 b.build()
780 }
781
782 pub fn enable_log(&self) {
784 self.log.set(true);
785 }
786
787 pub fn disable_log(&self) {
789 self.log.set(false);
790 }
791
792 pub fn enable_panic(&self) {
794 self.insta_panic.set(true);
795 }
796
797 pub fn disable_panic(&self) {
799 self.insta_panic.set(false);
800 }
801
802 pub fn widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
804 widget.build(self);
805 self
806 }
807
808 #[allow(clippy::collapsible_else_if)]
817 pub fn widget_navigate(
818 &mut self,
819 widget: &dyn HasFocus,
820 navigation: Navigation,
821 ) -> &mut Self {
822 widget.build(self);
823
824 let widget_flag = widget.focus();
825 if let Some(idx) = self.focus_flags.iter().position(|v| *v == widget_flag) {
827 focus_debug!(
828 self,
829 "override navigation for {:?} with {:?}",
830 widget_flag,
831 navigation
832 );
833
834 self.navigable[idx] = navigation;
835 } else {
836 if self.container_ids.contains(&widget_flag.widget_id()) {
837 focus_fail!(
838 self,
839 "FAIL to override navigation for {:?}. This is a container.",
840 widget_flag,
841 );
842 } else {
843 focus_fail!(
844 self,
845 "FAIL to override navigation for {:?}. Widget doesn't use this focus-flag",
846 widget_flag,
847 );
848 }
849 }
850
851 self
852 }
853
854 #[inline]
856 pub fn widgets<const N: usize>(&mut self, widgets: [&dyn HasFocus; N]) -> &mut Self {
857 for widget in widgets {
858 widget.build(self);
859 }
860 self
861 }
862
863 #[must_use]
876 pub fn start(&mut self, container: &dyn HasFocus) -> FocusFlag {
877 self.start_with_flags(container.focus(), container.area(), container.area_z())
878 }
879
880 pub fn end(&mut self, tag: FocusFlag) {
882 focus_debug!(self, "end container {:?}", tag);
883 assert!(self.container_ids.contains(&tag.widget_id()));
884
885 for (c, r) in self.containers.iter_mut().rev() {
886 if c.container_flag != tag {
887 if !c.complete {
888 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
889 }
890 } else {
891 r.end = self.focus_flags.len();
892 c.complete = true;
893
894 focus_debug!(self, "container range {:?}", r);
895
896 self.z_base -= c.delta_z;
897
898 break;
899 }
900 }
901 }
902
903 pub fn leaf_widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
915 self.widget_with_flags(
916 widget.focus(),
917 widget.area(),
918 widget.area_z(),
919 widget.navigable(),
920 );
921 self
922 }
923
924 pub fn widget_with_flags(
937 &mut self,
938 focus: FocusFlag,
939 area: Rect,
940 area_z: u16,
941 navigable: Navigation,
942 ) {
943 let duplicate = self.focus_ids.contains(&focus.widget_id());
944
945 if duplicate {
948 assert!(matches!(navigable, Navigation::Mouse | Navigation::None))
949 }
950
951 focus_debug!(self, "widget {:?}", focus);
952
953 self.focus_ids.insert(focus.widget_id());
954 self.focus_flags.push(focus);
955 self.duplicate.push(duplicate);
956 self.areas.push((area, self.z_base + area_z));
957 self.navigable.push(navigable);
958 }
959
960 #[must_use]
969 pub fn start_with_flags(
970 &mut self,
971 container_flag: FocusFlag,
972 area: Rect,
973 area_z: u16,
974 ) -> FocusFlag {
975 focus_debug!(self, "start container {:?}", container_flag);
976
977 assert!(!self.container_ids.contains(&container_flag.widget_id()));
979
980 self.z_base += area_z;
981
982 let len = self.focus_flags.len();
983 self.container_ids.insert(container_flag.widget_id());
984 self.containers.push((
985 Container {
986 container_flag: container_flag.clone(),
987 area: (area, self.z_base),
988 delta_z: area_z,
989 complete: false,
990 },
991 len..len,
992 ));
993
994 container_flag
995 }
996
997 pub fn build(mut self) -> Focus {
1003 for v in &self.last.focus_flags {
1005 if !self.focus_ids.contains(&v.widget_id()) {
1006 v.clear();
1007 }
1008 }
1009 for (v, _) in &self.last.containers {
1010 let have_container = self
1011 .containers
1012 .iter()
1013 .any(|(c, _)| v.container_flag == c.container_flag);
1014 if !have_container {
1015 v.container_flag.clear();
1016 }
1017 }
1018 self.last.clear();
1019
1020 for (c, _) in self.containers.iter_mut().rev() {
1022 if !c.complete {
1023 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
1024 }
1025 }
1026
1027 let log = self.last.log.get();
1028 let insta_panic = self.last.insta_panic.get();
1029
1030 Focus {
1031 last: self.last,
1032 core: FocusCore {
1033 log: Cell::new(log),
1034 insta_panic: Cell::new(insta_panic),
1035 focus_ids: self.focus_ids,
1036 focus_flags: self.focus_flags,
1037 duplicate: self.duplicate,
1038 areas: self.areas,
1039 navigable: self.navigable,
1040 container_ids: self.container_ids,
1041 containers: self.containers,
1042 },
1043 }
1044 }
1045 }
1046
1047 #[derive(Debug, Clone)]
1049 struct Container {
1050 container_flag: FocusFlag,
1054 area: (Rect, u16),
1057 delta_z: u16,
1059 complete: bool,
1061 }
1062
1063 #[derive(Debug, Default, Clone)]
1065 pub(super) struct FocusCore {
1066 pub(super) log: Cell<bool>,
1068 pub(super) insta_panic: Cell<bool>,
1069
1070 focus_ids: HashSet<usize, FxBuildHasher>,
1072 focus_flags: Vec<FocusFlag>,
1074 duplicate: Vec<bool>,
1077 areas: Vec<(Rect, u16)>,
1080 navigable: Vec<Navigation>,
1082 container_ids: HashSet<usize, FxBuildHasher>,
1084 containers: Vec<(Container, Range<usize>)>,
1089 }
1090
1091 impl FocusCore {
1092 pub(super) fn clear(&mut self) {
1094 self.focus_ids.clear();
1095 self.focus_flags.clear();
1096 self.duplicate.clear();
1097 self.areas.clear();
1098 self.navigable.clear();
1099 self.container_ids.clear();
1100 self.containers.clear();
1101 }
1102
1103 pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
1105 self.focus_flags
1106 .iter()
1107 .find(|v| widget_id == v.widget_id())
1108 .cloned()
1109 }
1110
1111 pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
1113 self.focus_ids.contains(&focus_flag.widget_id())
1114 }
1115
1116 pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
1118 self.focus_flags
1119 .iter()
1120 .enumerate()
1121 .find(|(_, f)| *f == focus_flag)
1122 .map(|(idx, _)| idx)
1123 }
1124
1125 pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
1127 self.container_ids.contains(&focus_flag.widget_id())
1128 }
1129
1130 pub(super) fn container_index_of(
1132 &self,
1133 container_flag: &FocusFlag,
1134 ) -> Option<(usize, Range<usize>)> {
1135 self.containers
1136 .iter()
1137 .enumerate()
1138 .find(|(_, (c, _))| &c.container_flag == container_flag)
1139 .map(|(idx, (_, range))| (idx, range.clone()))
1140 }
1141
1142 pub(super) fn insert_container(
1147 &mut self,
1148 idx: usize,
1149 cidx: usize,
1150 mut container: FocusCore,
1151 ) {
1152 for c in &self.focus_flags {
1153 for d in &container.focus_flags {
1154 assert_ne!(c, d);
1155 }
1156 }
1157
1158 let start = idx;
1160 let end = idx + container.focus_flags.len();
1161
1162 self.focus_ids.extend(container.focus_ids.iter());
1163 self.focus_flags
1164 .splice(idx..idx, container.focus_flags.drain(..));
1165 self.duplicate
1166 .splice(idx..idx, container.duplicate.drain(..));
1167 self.areas.splice(idx..idx, container.areas.drain(..));
1168 self.navigable
1169 .splice(idx..idx, container.navigable.drain(..));
1170
1171 for (_, r) in &mut self.containers {
1173 *r = Self::expand(start..end, r.clone());
1174 }
1175 self.containers.splice(
1177 cidx..cidx,
1178 container
1179 .containers
1180 .drain(..)
1181 .map(|(c, r)| (c, Self::shift(start, r))),
1182 );
1183 self.container_ids.extend(container.container_ids.iter());
1184 }
1185
1186 pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1189 let crange = self.containers[cidx].1.clone();
1190
1191 let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1193 let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1194 for f in focus_flags.iter() {
1195 self.focus_ids.remove(&f.widget_id());
1196 focus_ids.insert(f.widget_id());
1197 }
1198 let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1199 let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1200 let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1201 let sub_containers = self
1202 .containers
1203 .iter()
1204 .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1205 .cloned()
1206 .collect::<Vec<_>>();
1207 self.containers
1209 .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1210 let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1211 for (sc, _) in sub_containers.iter() {
1212 self.container_ids.remove(&sc.container_flag.widget_id());
1213 sub_container_ids.insert(sc.container_flag.widget_id());
1214 }
1215
1216 for (_, r) in &mut self.containers {
1218 *r = Self::shrink(crange.start..crange.end, r.clone());
1219 }
1220
1221 FocusCore {
1222 log: Cell::new(false),
1223 insta_panic: Cell::new(false),
1224 focus_ids,
1225 focus_flags,
1226 duplicate,
1227 areas,
1228 navigable,
1229 container_ids: sub_container_ids,
1230 containers: sub_containers,
1231 }
1232 }
1233
1234 fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1236 range.start + n..range.end + n
1237 }
1238
1239 fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1241 let len = insert.end - insert.start;
1242
1243 if range.start >= insert.start {
1244 range.start += len;
1245 }
1246 if range.end > insert.start {
1247 range.end += len;
1248 }
1249 range
1250 }
1251
1252 fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1254 let len = remove.end - remove.start;
1255
1256 if range.start < remove.start {
1257 } else if range.start >= remove.start && range.start <= remove.end {
1259 range.start = remove.start;
1260 } else {
1261 range.start -= len;
1262 }
1263
1264 if range.end < remove.start {
1265 } else if range.end >= remove.start && range.end <= remove.end {
1267 range.end = remove.start;
1268 } else {
1269 range.end -= len;
1270 }
1271
1272 range
1273 }
1274
1275 fn __start_change(&self, set_lost: bool) {
1278 for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1279 if *duplicate {
1280 continue;
1282 }
1283 if set_lost {
1284 f.set_lost(f.get());
1285 } else {
1286 f.set_lost(false);
1287 }
1288 f.set_gained(false);
1289 f.set(false);
1290 }
1291 }
1292
1293 fn __focus(&self, n: usize, set_lost: bool) -> bool {
1296 if let Some(f) = self.focus_flags.get(n) {
1297 focus_debug!(self, " -> focus {}:{:?}", n, f.name());
1298 f.set(true);
1299 if set_lost {
1300 if f.lost() {
1301 f.set_lost(false);
1304 f.set_gained(false);
1305 false
1306 } else {
1307 f.set_gained(true);
1308 true
1309 }
1310 } else {
1311 false
1312 }
1313 } else {
1314 false
1315 }
1316 }
1317
1318 #[allow(clippy::collapsible_if)]
1320 fn __accumulate(&self) {
1321 for (n, f) in self.focus_flags.iter().enumerate() {
1322 if f.gained() && !self.duplicate[n] {
1323 if let Some(on_gained_cb) = f.0.on_gained.borrow().as_ref() {
1324 focus_debug!(self, " -> notify_on_gained {}:{:?}", n, f.name());
1325 on_gained_cb();
1326 }
1327 }
1328 if f.lost() && !self.duplicate[n] {
1329 if let Some(on_lost_cb) = f.0.on_lost.borrow().as_ref() {
1330 focus_debug!(self, " -> notify_on_lost {}:{:?}", n, f.name());
1331 on_lost_cb();
1332 }
1333 }
1334 }
1335
1336 for (f, r) in &self.containers {
1337 let mut any_gained = false;
1338 let mut any_lost = false;
1339 let mut any_focused = false;
1340
1341 for idx in r.clone() {
1342 any_gained |= self.focus_flags[idx].gained();
1343 any_lost |= self.focus_flags[idx].lost();
1344 any_focused |= self.focus_flags[idx].get();
1345 }
1346
1347 f.container_flag.set(any_focused);
1348 f.container_flag.set_lost(any_lost && !any_gained);
1349 if any_lost && !any_gained {
1350 if let Some(on_lost_cb) = f.container_flag.0.on_lost.borrow().as_ref() {
1351 focus_debug!(
1352 self,
1353 "-> notify_on_lost container {:?}",
1354 f.container_flag.name()
1355 );
1356 on_lost_cb();
1357 }
1358 }
1359 f.container_flag.set_gained(any_gained && !any_lost);
1360 if any_gained && !any_lost {
1361 if let Some(on_gained_cb) = f.container_flag.0.on_gained.borrow().as_ref() {
1362 focus_debug!(
1363 self,
1364 "-> notify_on_gained container {:?}",
1365 f.container_flag.name()
1366 );
1367 on_gained_cb();
1368 }
1369 }
1370 }
1371 }
1372
1373 pub(super) fn reset(&self) {
1375 for f in self.focus_flags.iter() {
1376 f.set(false);
1377 f.set_lost(false);
1378 f.set_gained(false);
1379 }
1380 for (f, _) in self.containers.iter() {
1381 f.container_flag.set(false);
1382 f.container_flag.set_gained(false);
1383 f.container_flag.set_lost(false);
1384 }
1385 }
1386
1387 pub(super) fn reset_lost_gained(&self) {
1389 for f in self.focus_flags.iter() {
1390 f.set_lost(false);
1391 f.set_gained(false);
1392 }
1393 for (f, _) in self.containers.iter() {
1394 f.container_flag.set_gained(false);
1395 f.container_flag.set_lost(false);
1396 }
1397 }
1398
1399 pub(super) fn first(&self) {
1401 if let Some(n) = self.first_navigable(0) {
1402 self.__start_change(true);
1403 self.__focus(n, true);
1404 self.__accumulate();
1405 } else {
1406 focus_debug!(self, " -> no navigable widget");
1407 }
1408 }
1409
1410 pub(super) fn none(&self) {
1412 self.__start_change(true);
1413 self.__accumulate();
1414 }
1415
1416 pub(super) fn first_container(&self, container: &FocusFlag) {
1418 if let Some((_idx, range)) = self.container_index_of(container) {
1419 if let Some(n) = self.first_navigable(range.start) {
1420 if n < range.end {
1421 self.__start_change(true);
1422 self.__focus(n, true);
1423 self.__accumulate();
1424 } else {
1425 focus_debug!(self, " -> no navigable widget for container");
1426 }
1427 } else {
1428 focus_debug!(self, " -> no navigable widget");
1429 }
1430 } else {
1431 focus_fail!(self, " => container not found");
1432 }
1433 }
1434
1435 pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1437 self.__start_change(set_lost);
1438 self.__focus(n, set_lost);
1439 self.__accumulate();
1440 }
1441
1442 pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1446 let pos = (col, row).into();
1447
1448 enum ZOrder {
1449 Widget(usize),
1450 Container(usize),
1451 }
1452
1453 let mut z_order: Option<(ZOrder, u16)> = None;
1455 for (idx, (sub, _)) in self.containers.iter().enumerate() {
1458 if sub.area.0.contains(pos) {
1459 focus_debug!(
1460 self,
1461 " container area-match {:?}",
1462 sub.container_flag.name()
1463 );
1464
1465 z_order = if let Some(zz) = z_order {
1466 if zz.1 <= sub.area.1 {
1467 Some((ZOrder::Container(idx), sub.area.1))
1468 } else {
1469 Some(zz)
1470 }
1471 } else {
1472 Some((ZOrder::Container(idx), sub.area.1))
1473 };
1474 }
1475 }
1476 for (idx, area) in self.areas.iter().enumerate() {
1478 if area.0.contains(pos) {
1479 focus_debug!(self, " area-match {:?}", self.focus_flags[idx].name());
1480
1481 z_order = if let Some(zz) = z_order {
1482 if zz.1 <= area.1 {
1483 Some((ZOrder::Widget(idx), area.1))
1484 } else {
1485 Some(zz)
1486 }
1487 } else {
1488 Some((ZOrder::Widget(idx), area.1))
1489 };
1490 }
1491 }
1492
1493 if let Some((idx, _)) = z_order {
1495 match idx {
1496 ZOrder::Widget(idx) => {
1497 if self.navigable[idx] != Navigation::None {
1498 self.__start_change(true);
1499 let r = self.__focus(idx, true);
1500 self.__accumulate();
1501 return r;
1502 } else {
1503 focus_debug!(
1504 self,
1505 " -> not mouse reachable {:?}",
1506 self.focus_flags[idx].name()
1507 );
1508 return false;
1509 }
1510 }
1511 ZOrder::Container(idx) => {
1512 let range = &self.containers[idx].1;
1513 if let Some(n) = self.first_navigable(range.start) {
1514 self.__start_change(true);
1515 let r = self.__focus(n, true);
1516 self.__accumulate();
1517 return r;
1518 }
1519 }
1520 }
1521 }
1522
1523 focus_debug!(self, " -> no widget at pos");
1525
1526 false
1527 }
1528
1529 pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1531 if let Some((_idx, range)) = self.container_index_of(&flag) {
1532 self.__start_change(true);
1533 let n = self.next_navigable(range.end);
1534 self.__focus(n, true);
1535 self.__accumulate();
1536
1537 if flag.is_focused() {
1539 focus_debug!(self, " -> focus not usable. cleared");
1540 self.none();
1541 } else {
1542 focus_debug!(self, " -> expelled.");
1543 }
1544 true
1545 } else {
1546 focus_fail!(self, " => container not found");
1547 false
1548 }
1549 }
1550
1551 pub(super) fn next(&self) -> bool {
1553 self.__start_change(true);
1554 for (n, p) in self.focus_flags.iter().enumerate() {
1555 if p.lost() {
1556 let n = self.next_navigable(n);
1557 self.__focus(n, true);
1558 self.__accumulate();
1559 return true;
1560 }
1561 }
1562 if let Some(n) = self.first_navigable(0) {
1563 focus_debug!(
1564 self,
1565 " use first_navigable {}:{:?}",
1566 n,
1567 self.focus_flags[n].name()
1568 );
1569 self.__focus(n, true);
1570 self.__accumulate();
1571 return true;
1572 }
1573 focus_debug!(self, " -> no next");
1574 false
1575 }
1576
1577 pub(super) fn prev(&self) -> bool {
1579 self.__start_change(true);
1580 for (i, p) in self.focus_flags.iter().enumerate() {
1581 if p.lost() {
1582 let n = self.prev_navigable(i);
1583 self.__focus(n, true);
1584 self.__accumulate();
1585 return true;
1586 }
1587 }
1588 if let Some(n) = self.first_navigable(0) {
1589 focus_debug!(
1590 self,
1591 " use first_navigable {}:{:?}",
1592 n,
1593 self.focus_flags[n].name()
1594 );
1595 self.__focus(n, true);
1596 self.__accumulate();
1597 return true;
1598 }
1599 focus_debug!(self, " -> no prev");
1600 false
1601 }
1602
1603 pub(super) fn navigation(&self) -> Option<Navigation> {
1605 self.focus_flags
1606 .iter()
1607 .enumerate()
1608 .find(|(_, v)| v.get())
1609 .map(|(i, _)| self.navigable[i])
1610 }
1611
1612 pub(super) fn focused(&self) -> Option<FocusFlag> {
1614 self.focus_flags.iter().find(|v| v.get()).cloned()
1615 }
1616
1617 pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1619 self.focus_flags.iter().find(|v| v.lost()).cloned()
1620 }
1621
1622 pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1624 self.focus_flags.iter().find(|v| v.gained()).cloned()
1625 }
1626
1627 fn first_navigable(&self, start: usize) -> Option<usize> {
1629 focus_debug!(
1630 self,
1631 "first navigable, start at {}:{:?} ",
1632 start,
1633 if start < self.focus_flags.len() {
1634 self.focus_flags[start].name()
1635 } else {
1636 "beginning"
1637 }
1638 );
1639 for n in start..self.focus_flags.len() {
1640 if matches!(
1641 self.navigable[n],
1642 Navigation::Reach
1643 | Navigation::ReachLeaveBack
1644 | Navigation::ReachLeaveFront
1645 | Navigation::Regular
1646 ) {
1647 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1648 return Some(n);
1649 }
1650 }
1651 focus_debug!(self, " -> no first");
1652 None
1653 }
1654
1655 fn next_navigable(&self, start: usize) -> usize {
1657 focus_debug!(
1658 self,
1659 "next navigable after {}:{:?}",
1660 start,
1661 if start < self.focus_flags.len() {
1662 self.focus_flags[start].name()
1663 } else {
1664 "last"
1665 }
1666 );
1667
1668 let mut n = start;
1669 loop {
1670 n = if n + 1 < self.focus_flags.len() {
1671 n + 1
1672 } else {
1673 0
1674 };
1675 if matches!(
1676 self.navigable[n],
1677 Navigation::Reach
1678 | Navigation::ReachLeaveBack
1679 | Navigation::ReachLeaveFront
1680 | Navigation::Regular
1681 ) {
1682 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1683 return n;
1684 }
1685 if n == start {
1686 focus_debug!(self, " -> {}:end at start", n);
1687 return n;
1688 }
1689 }
1690 }
1691
1692 fn prev_navigable(&self, start: usize) -> usize {
1694 focus_debug!(
1695 self,
1696 "prev navigable before {}:{:?}",
1697 start,
1698 self.focus_flags[start].name()
1699 );
1700
1701 let mut n = start;
1702 loop {
1703 n = if n > 0 {
1704 n - 1
1705 } else {
1706 self.focus_flags.len() - 1
1707 };
1708 if matches!(
1709 self.navigable[n],
1710 Navigation::Reach
1711 | Navigation::ReachLeaveBack
1712 | Navigation::ReachLeaveFront
1713 | Navigation::Regular
1714 ) {
1715 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1716 return n;
1717 }
1718 if n == start {
1719 focus_debug!(self, " -> {}:end at start", n);
1720 return n;
1721 }
1722 }
1723 }
1724
1725 #[allow(clippy::type_complexity)]
1727 pub(super) fn clone_destruct(
1728 &self,
1729 ) -> (
1730 Vec<FocusFlag>,
1731 Vec<bool>,
1732 Vec<(Rect, u16)>,
1733 Vec<Navigation>,
1734 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1735 ) {
1736 (
1737 self.focus_flags.clone(),
1738 self.duplicate.clone(),
1739 self.areas.clone(),
1740 self.navigable.clone(),
1741 self.containers
1742 .iter()
1743 .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1744 .collect::<Vec<_>>(),
1745 )
1746 }
1747 }
1748
1749 #[cfg(test)]
1750 mod test {
1751 use crate::focus::core::FocusCore;
1752 use crate::{FocusBuilder, FocusFlag, HasFocus};
1753 use ratatui::layout::Rect;
1754
1755 #[test]
1756 fn test_change() {
1757 assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1758 assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1759
1760 assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1761 assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1762 assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1763 assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1764 assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1765
1766 assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1767 assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1768 assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1769 assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1770 assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1771
1772 assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1773 assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1774 assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1775 assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1776 assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1777
1778 assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1779 assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1780 assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1781 assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1782 assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1783 }
1784
1785 #[test]
1786 #[should_panic]
1787 fn test_double_insert() {
1788 let a = FocusFlag::named("a");
1789 let b = FocusFlag::named("b");
1790
1791 let mut fb = FocusBuilder::new(None);
1792 fb.widget(&a);
1793 fb.widget(&b);
1794 fb.widget(&a);
1795 fb.build();
1796 }
1797
1798 #[test]
1799 fn test_insert_remove() {
1800 let a = FocusFlag::named("a");
1801 let b = FocusFlag::named("b");
1802 let c = FocusFlag::named("c");
1803 let d = FocusFlag::named("d");
1804 let e = FocusFlag::named("e");
1805 let f = FocusFlag::named("f");
1806 let g = FocusFlag::named("g");
1807 let h = FocusFlag::named("h");
1808 let i = FocusFlag::named("i");
1809
1810 let mut fb = FocusBuilder::new(None);
1811 fb.widget(&a);
1812 fb.widget(&b);
1813 fb.widget(&c);
1814 let ff = fb.build();
1815 assert_eq!(ff.core.focus_flags[0], a);
1816 assert_eq!(ff.core.focus_flags[1], b);
1817 assert_eq!(ff.core.focus_flags[2], c);
1818
1819 let cc = FocusFlag::named("cc");
1820 let mut fb = FocusBuilder::new(None);
1821 fb.widget(&a);
1822 let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1823 fb.widget(&d);
1824 fb.widget(&e);
1825 fb.widget(&f);
1826 fb.end(cc_end);
1827 fb.widget(&b);
1828 fb.widget(&c);
1829 let mut ff = fb.build();
1830 assert_eq!(ff.core.focus_flags[0], a);
1831 assert_eq!(ff.core.focus_flags[1], d);
1832 assert_eq!(ff.core.focus_flags[2], e);
1833 assert_eq!(ff.core.focus_flags[3], f);
1834 assert_eq!(ff.core.focus_flags[4], b);
1835 assert_eq!(ff.core.focus_flags[5], c);
1836 assert_eq!(ff.core.containers[0].1, 1..4);
1837
1838 struct DD {
1839 dd: FocusFlag,
1840 g: FocusFlag,
1841 h: FocusFlag,
1842 i: FocusFlag,
1843 }
1844
1845 impl HasFocus for DD {
1846 fn build(&self, fb: &mut FocusBuilder) {
1847 let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1848 fb.widget(&self.g);
1849 fb.widget(&self.h);
1850 fb.widget(&self.i);
1851 fb.end(tag);
1852 }
1853
1854 fn focus(&self) -> FocusFlag {
1855 self.dd.clone()
1856 }
1857
1858 fn area(&self) -> Rect {
1859 Rect::default()
1860 }
1861 }
1862
1863 let dd = DD {
1864 dd: FocusFlag::named("dd"),
1865 g: g.clone(),
1866 h: h.clone(),
1867 i: i.clone(),
1868 };
1869 ff.replace_container(&cc, &dd);
1870 assert_eq!(ff.core.focus_flags[0], a);
1871 assert_eq!(ff.core.focus_flags[1], g);
1872 assert_eq!(ff.core.focus_flags[2], h);
1873 assert_eq!(ff.core.focus_flags[3], i);
1874 assert_eq!(ff.core.focus_flags[4], b);
1875 assert_eq!(ff.core.focus_flags[5], c);
1876 assert_eq!(ff.core.containers[0].1, 1..4);
1877 }
1878 }
1879}
1880
1881impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1882 #[inline(always)]
1883 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1884 match event {
1885 ct_event!(keycode press Tab) => {
1886 focus_debug!(
1887 self.core,
1888 "Tab {:?}",
1889 self.focused().map(|v| v.name().to_string())
1890 );
1891 let r = if self.next() {
1892 Outcome::Changed
1893 } else {
1894 Outcome::Continue
1895 };
1896 focus_debug!(
1897 self.core,
1898 " -> {:?}",
1899 self.focused().map(|v| v.name().to_string())
1900 );
1901 r
1902 }
1903 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1904 focus_debug!(
1905 self.core,
1906 "BackTab {:?}",
1907 self.focused().map(|v| v.name().to_string())
1908 );
1909 let r = if self.prev() {
1910 Outcome::Changed
1911 } else {
1912 Outcome::Continue
1913 };
1914 focus_debug!(
1915 self.core,
1916 " -> {:?}",
1917 self.focused().map(|v| v.name().to_string())
1918 );
1919 r
1920 }
1921 _ => self.handle(event, MouseOnly),
1922 }
1923 }
1924}
1925
1926impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1927 #[inline(always)]
1928 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1929 match event {
1930 ct_event!(mouse down Left for column, row) => {
1931 focus_debug!(self.core, "mouse down {},{}", column, row);
1932 if self.focus_at(*column, *row) {
1933 focus_debug!(
1934 self.core,
1935 " -> {:?}",
1936 self.focused().map(|v| v.name().to_string())
1937 );
1938 Outcome::Changed
1939 } else {
1940 self.reset_lost_gained();
1941 Outcome::Continue
1942 }
1943 }
1944 _ => {
1945 self.reset_lost_gained();
1946 Outcome::Continue
1947 }
1948 }
1949 }
1950}
1951
1952#[inline(always)]
1954pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1955 HandleEvent::handle(focus, event, Regular)
1956}