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)]
174 pub fn future(&self, widget_state: &'_ dyn HasFocus) {
175 focus_debug!(self.core, "focus {:?}", widget_state.focus().name());
176 let flag = widget_state.focus();
177 if self.core.is_widget(&flag) {
178 focus_fail!(
179 self.core,
180 " => widget is part of focus. use focus() instead"
181 );
182 } else if self.core.is_container(&flag) {
183 focus_debug!(self.core, "future container");
184 let had_focus = flag.get();
185 flag.set(true);
186 if !had_focus {
187 flag.set_gained(true);
188 flag.call_on_gained();
189 }
190 focus_debug!(self.core, " -> done");
191 } else {
192 focus_debug!(self.core, "future focus");
193 self.core.none();
194 flag.set(true);
195 flag.set_gained(true);
196 flag.call_on_gained();
197 focus_debug!(self.core, " -> done");
198 }
199 }
200
201 #[inline(always)]
210 pub fn focus_at(&self, col: u16, row: u16) -> bool {
211 focus_debug!(self.core, "focus at {},{}", col, row);
212 match self.navigation() {
213 Some(Navigation::Lock) => {
214 focus_debug!(self.core, " -> locked");
215 false
216 }
217 _ => self.core.focus_at(col, row),
218 }
219 }
220
221 #[inline]
231 pub fn next(&self) -> bool {
232 match self.navigation() {
233 None => {
234 self.first();
235 true
236 }
237 Some(Navigation::Leave | Navigation::ReachLeaveBack | Navigation::Regular) => {
238 focus_debug!(
239 self.core,
240 "next after {:?}",
241 self.core
242 .focused()
243 .map(|v| v.name().to_string())
244 .unwrap_or("None".into())
245 );
246 self.core.next()
247 }
248 v => {
249 focus_debug!(
250 self.core,
251 "next after {:?}, but navigation says {:?}",
252 self.core
253 .focused()
254 .map(|v| v.name().to_string())
255 .unwrap_or("None".into()),
256 v
257 );
258 false
259 }
260 }
261 }
262
263 #[inline]
273 pub fn prev(&self) -> bool {
274 match self.navigation() {
275 None => {
276 self.first();
277 true
278 }
279 Some(Navigation::Leave | Navigation::ReachLeaveFront | Navigation::Regular) => {
280 focus_debug!(
281 self.core,
282 "prev before {:?}",
283 self.core
284 .focused()
285 .map(|v| v.name().to_string())
286 .unwrap_or("None".into())
287 );
288 self.core.prev()
289 }
290 v => {
291 focus_debug!(
292 self.core,
293 "prev before {:?}, but navigation says {:?}",
294 self.core
295 .focused()
296 .map(|v| v.name().to_string())
297 .unwrap_or("None".into()),
298 v
299 );
300 false
301 }
302 }
303 }
304
305 #[inline]
317 pub fn next_force(&self) -> bool {
318 match self.navigation() {
319 None => {
320 self.first();
321 true
322 }
323 Some(
324 Navigation::Leave
325 | Navigation::Reach
326 | Navigation::ReachLeaveFront
327 | Navigation::ReachLeaveBack
328 | Navigation::Regular,
329 ) => {
330 focus_debug!(
331 self.core,
332 "force next after {:?}",
333 self.core.focused().map(|v| v.name().to_string())
334 );
335 self.core.next()
336 }
337 v => {
338 focus_debug!(
339 self.core,
340 "force next after {:?}, but navigation says {:?}",
341 self.core.focused().map(|v| v.name().to_string()),
342 v
343 );
344 false
345 }
346 }
347 }
348
349 #[inline]
361 pub fn prev_force(&self) -> bool {
362 match self.navigation() {
363 None => {
364 self.first();
365 true
366 }
367 Some(
368 Navigation::Leave
369 | Navigation::Reach
370 | Navigation::ReachLeaveFront
371 | Navigation::ReachLeaveBack
372 | Navigation::Regular,
373 ) => {
374 focus_debug!(
375 self.core,
376 "force prev before {:?}",
377 self.core.focused().map(|v| v.name().to_string())
378 );
379 self.core.prev()
380 }
381 v => {
382 focus_debug!(
383 self.core,
384 "force prev before {:?}, but navigation says {:?}",
385 self.core.focused().map(|v| v.name().to_string()),
386 v
387 );
388 false
389 }
390 }
391 }
392
393 #[inline(always)]
395 pub fn is_valid_widget(&self, widget_state: &'_ dyn HasFocus) -> bool {
396 self.core.is_widget(&widget_state.focus())
397 }
398
399 #[inline(always)]
401 pub fn is_valid_container(&self, widget_state: &'_ dyn HasFocus) -> bool {
402 self.core.is_container(&widget_state.focus())
403 }
404
405 #[inline(always)]
410 pub fn focused(&self) -> Option<FocusFlag> {
411 self.core.focused()
412 }
413
414 #[inline(always)]
419 pub fn focused_widget_id(&self) -> Option<usize> {
420 self.core.focused().map(|v| v.id())
421 }
422
423 #[inline(always)]
425 pub fn focused_name(&self) -> Option<String> {
426 self.core.focused().map(|v| v.name().to_string())
427 }
428
429 #[inline(always)]
431 pub fn navigation(&self) -> Option<Navigation> {
432 self.core.navigation()
433 }
434
435 #[inline(always)]
440 pub fn lost_focus(&self) -> Option<FocusFlag> {
441 self.core.lost_focus()
442 }
443
444 #[inline(always)]
449 pub fn gained_focus(&self) -> Option<FocusFlag> {
450 self.core.gained_focus()
451 }
452
453 #[inline]
468 pub fn focus_no_lost(&self, widget_state: &'_ dyn HasFocus) {
469 focus_debug!(self.core, "focus no_lost {:?}", widget_state.focus().name());
470 let flag = widget_state.focus();
471 if self.core.is_widget(&flag) {
472 if let Some(n) = self.core.index_of(&flag) {
473 self.core.focus_idx(n, false);
474 } else {
475 panic!(" => invalid widget");
476 }
477 } else if self.core.is_container(&flag) {
478 self.core.first_container(&flag);
479 } else {
480 focus_fail!(self.core, " => not a valid widget");
481 }
482 }
483
484 #[inline]
496 pub fn expel_focus(&self, widget_state: &'_ dyn HasFocus) {
497 focus_debug!(
498 self.core,
499 "expel from widget {:?}",
500 widget_state.focus().name()
501 );
502 let flag = widget_state.focus();
503 if self.core.is_widget(&flag) {
504 if self.core.index_of(&flag).is_some() {
505 if widget_state.is_focused() {
506 self.core.next();
507 if widget_state.is_focused() {
508 focus_debug!(self.core, " -> no other focus, cleared");
509 flag.clear();
510 } else {
511 focus_debug!(self.core, " -> expelled");
512 }
513 } else {
514 focus_debug!(self.core, " => widget not focused");
515 }
516 } else {
517 panic!(" => invalid widget");
518 }
519 } else if self.core.is_container(&flag) {
520 if flag.is_focused() {
521 self.core.expel_container(flag);
522 } else {
523 focus_debug!(self.core, " => container not focused");
524 }
525 } else {
526 focus_fail!(self.core, " => not a valid widget");
527 }
528 }
529
530 pub fn remove_container(&mut self, container: &'_ dyn HasFocus) {
538 focus_debug!(
539 self.core,
540 "focus remove container {:?} ",
541 container.focus().name()
542 );
543 let flag = container.focus();
544 if self.core.is_container(&flag) {
545 if let Some((cidx, _)) = self.core.container_index_of(&flag) {
546 self.core.remove_container(cidx).reset();
547 focus_debug!(self.core, " -> removed");
548 } else {
549 panic!(" => invalid container?");
550 }
551 } else {
552 focus_fail!(self.core, " => no container flag");
553 }
554 }
555
556 pub fn update_container(&mut self, container: &'_ dyn HasFocus) {
567 focus_debug!(
568 self.core,
569 "focus update container {:?} ",
570 container.focus().name()
571 );
572 let flag = container.focus();
573 if self.core.is_container(&flag) {
574 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
575 let removed = self.core.remove_container(cidx);
576
577 let mut b = FocusBuilder::new(Some(Focus {
578 last: Default::default(),
579 core: removed,
580 }));
581 b.widget(container);
582 let insert = b.build();
583
584 self.core.insert_container(range.start, cidx, insert.core);
585
586 focus_debug!(self.core, " -> updated");
587 } else {
588 panic!(" => invalid container?");
589 }
590 } else {
591 focus_fail!(self.core, " => no container flag");
592 }
593 }
594
595 pub fn replace_container(&mut self, container: &'_ dyn HasFocus, new: &'_ dyn HasFocus) {
609 focus_debug!(
610 self.core,
611 "focus replace container {:?} with {:?} ",
612 container.focus().name(),
613 new.focus().name()
614 );
615 let flag = container.focus();
616 if self.core.is_container(&flag) {
617 if let Some((cidx, range)) = self.core.container_index_of(&flag) {
618 let removed = self.core.remove_container(cidx);
619
620 let mut b = FocusBuilder::new(Some(Focus {
621 last: Default::default(),
622 core: removed,
623 }));
624 b.widget(new);
625 let insert = b.build();
626
627 self.core.insert_container(range.start, cidx, insert.core);
628
629 focus_debug!(self.core, " -> replaced");
630 } else {
631 panic!(" => invalid container");
632 }
633 } else {
634 focus_fail!(self.core, " => no container flag");
635 }
636 }
637
638 #[inline(always)]
645 pub fn reset_lost_gained(&self) {
646 self.core.reset_lost_gained();
647 }
648
649 #[allow(clippy::type_complexity)]
651 pub fn clone_destruct(
652 &self,
653 ) -> (
654 Vec<FocusFlag>,
655 Vec<bool>,
656 Vec<(Rect, u16)>,
657 Vec<Navigation>,
658 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
659 ) {
660 self.core.clone_destruct()
661 }
662}
663
664mod core {
665 use crate::{Focus, FocusFlag, HasFocus, Navigation};
666 use fxhash::FxBuildHasher;
667 use ratatui::layout::Rect;
668 use std::cell::Cell;
669 use std::collections::HashSet;
670 use std::ops::Range;
671
672 #[derive(Debug, Default)]
674 pub struct FocusBuilder {
675 last: FocusCore,
676
677 log: Cell<bool>,
678 insta_panic: Cell<bool>,
679
680 z_base: u16,
688
689 focus_ids: HashSet<usize, FxBuildHasher>,
691 focus_flags: Vec<FocusFlag>,
692 duplicate: Vec<bool>,
693 areas: Vec<(Rect, u16)>,
694 navigable: Vec<Navigation>,
695 container_ids: HashSet<usize, FxBuildHasher>,
696 containers: Vec<(Container, Range<usize>)>,
697 }
698
699 impl FocusBuilder {
700 pub fn new(last: Option<Focus>) -> FocusBuilder {
708 if let Some(mut last) = last {
709 last.last.clear();
711
712 Self {
713 last: last.core,
714 log: Default::default(),
715 insta_panic: Default::default(),
716 z_base: 0,
717 focus_ids: last.last.focus_ids,
718 focus_flags: last.last.focus_flags,
719 duplicate: last.last.duplicate,
720 areas: last.last.areas,
721 navigable: last.last.navigable,
722 container_ids: last.last.container_ids,
723 containers: last.last.containers,
724 }
725 } else {
726 Self {
727 last: FocusCore::default(),
728 log: Default::default(),
729 insta_panic: Default::default(),
730 z_base: Default::default(),
731 focus_ids: Default::default(),
732 focus_flags: Default::default(),
733 duplicate: Default::default(),
734 areas: Default::default(),
735 navigable: Default::default(),
736 container_ids: Default::default(),
737 containers: Default::default(),
738 }
739 }
740 }
741
742 pub fn log_build_for(container: &dyn HasFocus) -> Focus {
744 let mut b = FocusBuilder::new(None);
745 b.enable_log();
746 b.widget(container);
747 b.build()
748 }
749
750 pub fn build_for(container: &dyn HasFocus) -> Focus {
763 let mut b = FocusBuilder::new(None);
764 b.widget(container);
765 b.build()
766 }
767
768 pub fn log_rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
770 let mut b = FocusBuilder::new(old);
771 b.enable_log();
772 b.widget(container);
773 b.build()
774 }
775
776 pub fn rebuild_for(container: &dyn HasFocus, old: Option<Focus>) -> Focus {
783 let mut b = FocusBuilder::new(old);
784 b.widget(container);
785 b.build()
786 }
787
788 pub fn enable_log(&self) {
790 self.log.set(true);
791 }
792
793 pub fn disable_log(&self) {
795 self.log.set(false);
796 }
797
798 pub fn enable_panic(&self) {
800 self.insta_panic.set(true);
801 }
802
803 pub fn disable_panic(&self) {
805 self.insta_panic.set(false);
806 }
807
808 pub fn widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
810 widget.build(self);
811 self
812 }
813
814 #[allow(clippy::collapsible_else_if)]
823 pub fn widget_navigate(
824 &mut self,
825 widget: &dyn HasFocus,
826 navigation: Navigation,
827 ) -> &mut Self {
828 widget.build(self);
829
830 let widget_flag = widget.focus();
831 if let Some(idx) = self.focus_flags.iter().position(|v| *v == widget_flag) {
833 focus_debug!(
834 self,
835 "override navigation for {:?} with {:?}",
836 widget_flag,
837 navigation
838 );
839
840 self.navigable[idx] = navigation;
841 } else {
842 if self.container_ids.contains(&widget_flag.widget_id()) {
843 focus_fail!(
844 self,
845 "FAIL to override navigation for {:?}. This is a container.",
846 widget_flag,
847 );
848 } else {
849 focus_fail!(
850 self,
851 "FAIL to override navigation for {:?}. Widget doesn't use this focus-flag",
852 widget_flag,
853 );
854 }
855 }
856
857 self
858 }
859
860 #[inline]
862 pub fn widgets<const N: usize>(&mut self, widgets: [&dyn HasFocus; N]) -> &mut Self {
863 for widget in widgets {
864 widget.build(self);
865 }
866 self
867 }
868
869 #[must_use]
882 pub fn start(&mut self, container: &dyn HasFocus) -> FocusFlag {
883 self.start_with_flags(container.focus(), container.area(), container.area_z())
884 }
885
886 pub fn end(&mut self, tag: FocusFlag) {
888 focus_debug!(self, "end container {:?}", tag);
889 assert!(self.container_ids.contains(&tag.widget_id()));
890
891 for (c, r) in self.containers.iter_mut().rev() {
892 if c.container_flag != tag {
893 if !c.complete {
894 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
895 }
896 } else {
897 r.end = self.focus_flags.len();
898 c.complete = true;
899
900 focus_debug!(self, "container range {:?}", r);
901
902 self.z_base -= c.delta_z;
903
904 break;
905 }
906 }
907 }
908
909 pub fn leaf_widget(&mut self, widget: &dyn HasFocus) -> &mut Self {
921 self.widget_with_flags(
922 widget.focus(),
923 widget.area(),
924 widget.area_z(),
925 widget.navigable(),
926 );
927 self
928 }
929
930 pub fn widget_with_flags(
943 &mut self,
944 focus: FocusFlag,
945 area: Rect,
946 area_z: u16,
947 navigable: Navigation,
948 ) {
949 let duplicate = self.focus_ids.contains(&focus.widget_id());
950
951 if duplicate {
954 assert!(matches!(navigable, Navigation::Mouse | Navigation::None))
955 }
956
957 focus_debug!(self, "widget {:?}", focus);
958
959 self.focus_ids.insert(focus.widget_id());
960 self.focus_flags.push(focus);
961 self.duplicate.push(duplicate);
962 self.areas.push((area, self.z_base + area_z));
963 self.navigable.push(navigable);
964 }
965
966 #[must_use]
975 pub fn start_with_flags(
976 &mut self,
977 container_flag: FocusFlag,
978 area: Rect,
979 area_z: u16,
980 ) -> FocusFlag {
981 focus_debug!(self, "start container {:?}", container_flag);
982
983 assert!(!self.container_ids.contains(&container_flag.widget_id()));
985
986 self.z_base += area_z;
987
988 let len = self.focus_flags.len();
989 self.container_ids.insert(container_flag.widget_id());
990 self.containers.push((
991 Container {
992 container_flag: container_flag.clone(),
993 area: (area, self.z_base),
994 delta_z: area_z,
995 complete: false,
996 },
997 len..len,
998 ));
999
1000 container_flag
1001 }
1002
1003 pub fn build(mut self) -> Focus {
1009 for v in &self.last.focus_flags {
1011 if !self.focus_ids.contains(&v.widget_id()) {
1012 v.clear();
1013 }
1014 }
1015 for (v, _) in &self.last.containers {
1016 let have_container = self
1017 .containers
1018 .iter()
1019 .any(|(c, _)| v.container_flag == c.container_flag);
1020 if !have_container {
1021 v.container_flag.clear();
1022 }
1023 }
1024 self.last.clear();
1025
1026 for (c, _) in self.containers.iter_mut().rev() {
1028 if !c.complete {
1029 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
1030 }
1031 }
1032
1033 let log = self.last.log.get();
1034 let insta_panic = self.last.insta_panic.get();
1035
1036 Focus {
1037 last: self.last,
1038 core: FocusCore {
1039 log: Cell::new(log),
1040 insta_panic: Cell::new(insta_panic),
1041 focus_ids: self.focus_ids,
1042 focus_flags: self.focus_flags,
1043 duplicate: self.duplicate,
1044 areas: self.areas,
1045 navigable: self.navigable,
1046 container_ids: self.container_ids,
1047 containers: self.containers,
1048 },
1049 }
1050 }
1051 }
1052
1053 #[derive(Debug, Clone)]
1055 struct Container {
1056 container_flag: FocusFlag,
1060 area: (Rect, u16),
1063 delta_z: u16,
1065 complete: bool,
1067 }
1068
1069 #[derive(Debug, Default, Clone)]
1071 pub(super) struct FocusCore {
1072 pub(super) log: Cell<bool>,
1074 pub(super) insta_panic: Cell<bool>,
1075
1076 focus_ids: HashSet<usize, FxBuildHasher>,
1078 focus_flags: Vec<FocusFlag>,
1080 duplicate: Vec<bool>,
1083 areas: Vec<(Rect, u16)>,
1086 navigable: Vec<Navigation>,
1088 container_ids: HashSet<usize, FxBuildHasher>,
1090 containers: Vec<(Container, Range<usize>)>,
1095 }
1096
1097 impl FocusCore {
1098 pub(super) fn clear(&mut self) {
1100 self.focus_ids.clear();
1101 self.focus_flags.clear();
1102 self.duplicate.clear();
1103 self.areas.clear();
1104 self.navigable.clear();
1105 self.container_ids.clear();
1106 self.containers.clear();
1107 }
1108
1109 pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
1111 self.focus_flags
1112 .iter()
1113 .find(|v| widget_id == v.widget_id())
1114 .cloned()
1115 }
1116
1117 pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
1119 self.focus_ids.contains(&focus_flag.widget_id())
1120 }
1121
1122 pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
1124 self.focus_flags
1125 .iter()
1126 .enumerate()
1127 .find(|(_, f)| *f == focus_flag)
1128 .map(|(idx, _)| idx)
1129 }
1130
1131 pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
1133 self.container_ids.contains(&focus_flag.widget_id())
1134 }
1135
1136 pub(super) fn container_index_of(
1138 &self,
1139 container_flag: &FocusFlag,
1140 ) -> Option<(usize, Range<usize>)> {
1141 self.containers
1142 .iter()
1143 .enumerate()
1144 .find(|(_, (c, _))| &c.container_flag == container_flag)
1145 .map(|(idx, (_, range))| (idx, range.clone()))
1146 }
1147
1148 pub(super) fn insert_container(
1153 &mut self,
1154 idx: usize,
1155 cidx: usize,
1156 mut container: FocusCore,
1157 ) {
1158 for c in &self.focus_flags {
1159 for d in &container.focus_flags {
1160 assert_ne!(c, d);
1161 }
1162 }
1163
1164 let start = idx;
1166 let end = idx + container.focus_flags.len();
1167
1168 self.focus_ids.extend(container.focus_ids.iter());
1169 self.focus_flags
1170 .splice(idx..idx, container.focus_flags.drain(..));
1171 self.duplicate
1172 .splice(idx..idx, container.duplicate.drain(..));
1173 self.areas.splice(idx..idx, container.areas.drain(..));
1174 self.navigable
1175 .splice(idx..idx, container.navigable.drain(..));
1176
1177 for (_, r) in &mut self.containers {
1179 *r = Self::expand(start..end, r.clone());
1180 }
1181 self.containers.splice(
1183 cidx..cidx,
1184 container
1185 .containers
1186 .drain(..)
1187 .map(|(c, r)| (c, Self::shift(start, r))),
1188 );
1189 self.container_ids.extend(container.container_ids.iter());
1190 }
1191
1192 pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1195 let crange = self.containers[cidx].1.clone();
1196
1197 let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1199 let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1200 for f in focus_flags.iter() {
1201 self.focus_ids.remove(&f.widget_id());
1202 focus_ids.insert(f.widget_id());
1203 }
1204 let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1205 let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1206 let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1207 let sub_containers = self
1208 .containers
1209 .iter()
1210 .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1211 .cloned()
1212 .collect::<Vec<_>>();
1213 self.containers
1215 .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1216 let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1217 for (sc, _) in sub_containers.iter() {
1218 self.container_ids.remove(&sc.container_flag.widget_id());
1219 sub_container_ids.insert(sc.container_flag.widget_id());
1220 }
1221
1222 for (_, r) in &mut self.containers {
1224 *r = Self::shrink(crange.start..crange.end, r.clone());
1225 }
1226
1227 FocusCore {
1228 log: Cell::new(false),
1229 insta_panic: Cell::new(false),
1230 focus_ids,
1231 focus_flags,
1232 duplicate,
1233 areas,
1234 navigable,
1235 container_ids: sub_container_ids,
1236 containers: sub_containers,
1237 }
1238 }
1239
1240 fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1242 range.start + n..range.end + n
1243 }
1244
1245 fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1247 let len = insert.end - insert.start;
1248
1249 if range.start >= insert.start {
1250 range.start += len;
1251 }
1252 if range.end > insert.start {
1253 range.end += len;
1254 }
1255 range
1256 }
1257
1258 fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1260 let len = remove.end - remove.start;
1261
1262 if range.start < remove.start {
1263 } else if range.start >= remove.start && range.start <= remove.end {
1265 range.start = remove.start;
1266 } else {
1267 range.start -= len;
1268 }
1269
1270 if range.end < remove.start {
1271 } else if range.end >= remove.start && range.end <= remove.end {
1273 range.end = remove.start;
1274 } else {
1275 range.end -= len;
1276 }
1277
1278 range
1279 }
1280
1281 fn __start_change(&self, set_lost: bool) {
1284 for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1285 if *duplicate {
1286 continue;
1288 }
1289 if set_lost {
1290 f.set_lost(f.get());
1291 } else {
1292 f.set_lost(false);
1293 }
1294 f.set_gained(false);
1295 f.set(false);
1296 }
1297 }
1298
1299 fn __focus(&self, n: usize, set_lost: bool) -> bool {
1302 if let Some(f) = self.focus_flags.get(n) {
1303 focus_debug!(self, " -> focus {}:{:?}", n, f.name());
1304 f.set(true);
1305 if set_lost {
1306 if f.lost() {
1307 f.set_lost(false);
1310 f.set_gained(false);
1311 false
1312 } else {
1313 f.set_gained(true);
1314 true
1315 }
1316 } else {
1317 false
1318 }
1319 } else {
1320 false
1321 }
1322 }
1323
1324 #[allow(clippy::collapsible_if)]
1326 fn __accumulate(&self) {
1327 for (n, f) in self.focus_flags.iter().enumerate() {
1328 if f.gained() && !self.duplicate[n] {
1329 if let Some(on_gained_cb) = f.0.on_gained.borrow().as_ref() {
1330 focus_debug!(self, " -> notify_on_gained {}:{:?}", n, f.name());
1331 on_gained_cb();
1332 }
1333 }
1334 if f.lost() && !self.duplicate[n] {
1335 if let Some(on_lost_cb) = f.0.on_lost.borrow().as_ref() {
1336 focus_debug!(self, " -> notify_on_lost {}:{:?}", n, f.name());
1337 on_lost_cb();
1338 }
1339 }
1340 }
1341
1342 for (f, r) in &self.containers {
1343 let mut any_gained = false;
1344 let mut any_lost = false;
1345 let mut any_focused = false;
1346
1347 for idx in r.clone() {
1348 any_gained |= self.focus_flags[idx].gained();
1349 any_lost |= self.focus_flags[idx].lost();
1350 any_focused |= self.focus_flags[idx].get();
1351 }
1352
1353 f.container_flag.set(any_focused);
1354 f.container_flag.set_lost(any_lost && !any_gained);
1355 if any_lost && !any_gained {
1356 if let Some(on_lost_cb) = f.container_flag.0.on_lost.borrow().as_ref() {
1357 focus_debug!(
1358 self,
1359 "-> notify_on_lost container {:?}",
1360 f.container_flag.name()
1361 );
1362 on_lost_cb();
1363 }
1364 }
1365 f.container_flag.set_gained(any_gained && !any_lost);
1366 if any_gained && !any_lost {
1367 if let Some(on_gained_cb) = f.container_flag.0.on_gained.borrow().as_ref() {
1368 focus_debug!(
1369 self,
1370 "-> notify_on_gained container {:?}",
1371 f.container_flag.name()
1372 );
1373 on_gained_cb();
1374 }
1375 }
1376 }
1377 }
1378
1379 pub(super) fn reset(&self) {
1381 for f in self.focus_flags.iter() {
1382 f.set(false);
1383 f.set_lost(false);
1384 f.set_gained(false);
1385 }
1386 for (f, _) in self.containers.iter() {
1387 f.container_flag.set(false);
1388 f.container_flag.set_gained(false);
1389 f.container_flag.set_lost(false);
1390 }
1391 }
1392
1393 pub(super) fn reset_lost_gained(&self) {
1395 for f in self.focus_flags.iter() {
1396 f.set_lost(false);
1397 f.set_gained(false);
1398 }
1399 for (f, _) in self.containers.iter() {
1400 f.container_flag.set_gained(false);
1401 f.container_flag.set_lost(false);
1402 }
1403 }
1404
1405 pub(super) fn first(&self) {
1407 if let Some(n) = self.first_navigable(0) {
1408 self.__start_change(true);
1409 self.__focus(n, true);
1410 self.__accumulate();
1411 } else {
1412 focus_debug!(self, " -> no navigable widget");
1413 }
1414 }
1415
1416 pub(super) fn none(&self) {
1418 self.__start_change(true);
1419 self.__accumulate();
1420 }
1421
1422 pub(super) fn first_container(&self, container: &FocusFlag) {
1424 if let Some((_idx, range)) = self.container_index_of(container) {
1425 if let Some(n) = self.first_navigable(range.start) {
1426 if n < range.end {
1427 self.__start_change(true);
1428 self.__focus(n, true);
1429 self.__accumulate();
1430 } else {
1431 focus_debug!(self, " -> no navigable widget for container");
1432 }
1433 } else {
1434 focus_debug!(self, " -> no navigable widget");
1435 }
1436 } else {
1437 focus_fail!(self, " => container not found");
1438 }
1439 }
1440
1441 pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1443 self.__start_change(set_lost);
1444 self.__focus(n, set_lost);
1445 self.__accumulate();
1446 }
1447
1448 pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1452 let pos = (col, row).into();
1453
1454 enum ZOrder {
1455 Widget(usize),
1456 Container(usize),
1457 }
1458
1459 let mut z_order: Option<(ZOrder, u16)> = None;
1461 for (idx, (sub, _)) in self.containers.iter().enumerate() {
1464 if sub.area.0.contains(pos) {
1465 focus_debug!(
1466 self,
1467 " container area-match {:?}",
1468 sub.container_flag.name()
1469 );
1470
1471 z_order = if let Some(zz) = z_order {
1472 if zz.1 <= sub.area.1 {
1473 Some((ZOrder::Container(idx), sub.area.1))
1474 } else {
1475 Some(zz)
1476 }
1477 } else {
1478 Some((ZOrder::Container(idx), sub.area.1))
1479 };
1480 }
1481 }
1482 for (idx, area) in self.areas.iter().enumerate() {
1484 if area.0.contains(pos) {
1485 focus_debug!(self, " area-match {:?}", self.focus_flags[idx].name());
1486
1487 z_order = if let Some(zz) = z_order {
1488 if zz.1 <= area.1 {
1489 Some((ZOrder::Widget(idx), area.1))
1490 } else {
1491 Some(zz)
1492 }
1493 } else {
1494 Some((ZOrder::Widget(idx), area.1))
1495 };
1496 }
1497 }
1498
1499 if let Some((idx, _)) = z_order {
1501 match idx {
1502 ZOrder::Widget(idx) => {
1503 if self.navigable[idx] != Navigation::None {
1504 self.__start_change(true);
1505 let r = self.__focus(idx, true);
1506 self.__accumulate();
1507 return r;
1508 } else {
1509 focus_debug!(
1510 self,
1511 " -> not mouse reachable {:?}",
1512 self.focus_flags[idx].name()
1513 );
1514 return false;
1515 }
1516 }
1517 ZOrder::Container(idx) => {
1518 let range = &self.containers[idx].1;
1519 if let Some(n) = self.first_navigable(range.start) {
1520 self.__start_change(true);
1521 let r = self.__focus(n, true);
1522 self.__accumulate();
1523 return r;
1524 }
1525 }
1526 }
1527 }
1528
1529 focus_debug!(self, " -> no widget at pos");
1531
1532 false
1533 }
1534
1535 pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1537 if let Some((_idx, range)) = self.container_index_of(&flag) {
1538 self.__start_change(true);
1539 let n = self.next_navigable(range.end);
1540 self.__focus(n, true);
1541 self.__accumulate();
1542
1543 if flag.is_focused() {
1545 focus_debug!(self, " -> focus not usable. cleared");
1546 self.none();
1547 } else {
1548 focus_debug!(self, " -> expelled.");
1549 }
1550 true
1551 } else {
1552 focus_fail!(self, " => container not found");
1553 false
1554 }
1555 }
1556
1557 pub(super) fn next(&self) -> bool {
1559 self.__start_change(true);
1560 for (n, p) in self.focus_flags.iter().enumerate() {
1561 if p.lost() {
1562 let n = self.next_navigable(n);
1563 self.__focus(n, true);
1564 self.__accumulate();
1565 return true;
1566 }
1567 }
1568 if let Some(n) = self.first_navigable(0) {
1569 focus_debug!(
1570 self,
1571 " use first_navigable {}:{:?}",
1572 n,
1573 self.focus_flags[n].name()
1574 );
1575 self.__focus(n, true);
1576 self.__accumulate();
1577 return true;
1578 }
1579 focus_debug!(self, " -> no next");
1580 false
1581 }
1582
1583 pub(super) fn prev(&self) -> bool {
1585 self.__start_change(true);
1586 for (i, p) in self.focus_flags.iter().enumerate() {
1587 if p.lost() {
1588 let n = self.prev_navigable(i);
1589 self.__focus(n, true);
1590 self.__accumulate();
1591 return true;
1592 }
1593 }
1594 if let Some(n) = self.first_navigable(0) {
1595 focus_debug!(
1596 self,
1597 " use first_navigable {}:{:?}",
1598 n,
1599 self.focus_flags[n].name()
1600 );
1601 self.__focus(n, true);
1602 self.__accumulate();
1603 return true;
1604 }
1605 focus_debug!(self, " -> no prev");
1606 false
1607 }
1608
1609 pub(super) fn navigation(&self) -> Option<Navigation> {
1611 self.focus_flags
1612 .iter()
1613 .enumerate()
1614 .find(|(_, v)| v.get())
1615 .map(|(i, _)| self.navigable[i])
1616 }
1617
1618 pub(super) fn focused(&self) -> Option<FocusFlag> {
1620 self.focus_flags.iter().find(|v| v.get()).cloned()
1621 }
1622
1623 pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1625 self.focus_flags.iter().find(|v| v.lost()).cloned()
1626 }
1627
1628 pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1630 self.focus_flags.iter().find(|v| v.gained()).cloned()
1631 }
1632
1633 fn first_navigable(&self, start: usize) -> Option<usize> {
1635 focus_debug!(
1636 self,
1637 "first navigable, start at {}:{:?} ",
1638 start,
1639 if start < self.focus_flags.len() {
1640 self.focus_flags[start].name()
1641 } else {
1642 "beginning"
1643 }
1644 );
1645 for n in start..self.focus_flags.len() {
1646 if matches!(
1647 self.navigable[n],
1648 Navigation::Reach
1649 | Navigation::ReachLeaveBack
1650 | Navigation::ReachLeaveFront
1651 | Navigation::Regular
1652 ) {
1653 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1654 return Some(n);
1655 }
1656 }
1657 focus_debug!(self, " -> no first");
1658 None
1659 }
1660
1661 fn next_navigable(&self, start: usize) -> usize {
1663 focus_debug!(
1664 self,
1665 "next navigable after {}:{:?}",
1666 start,
1667 if start < self.focus_flags.len() {
1668 self.focus_flags[start].name()
1669 } else {
1670 "last"
1671 }
1672 );
1673
1674 let mut n = start;
1675 loop {
1676 n = if n + 1 < self.focus_flags.len() {
1677 n + 1
1678 } else {
1679 0
1680 };
1681 if matches!(
1682 self.navigable[n],
1683 Navigation::Reach
1684 | Navigation::ReachLeaveBack
1685 | Navigation::ReachLeaveFront
1686 | Navigation::Regular
1687 ) {
1688 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1689 return n;
1690 }
1691 if n == start {
1692 focus_debug!(self, " -> {}:end at start", n);
1693 return n;
1694 }
1695 }
1696 }
1697
1698 fn prev_navigable(&self, start: usize) -> usize {
1700 focus_debug!(
1701 self,
1702 "prev navigable before {}:{:?}",
1703 start,
1704 self.focus_flags[start].name()
1705 );
1706
1707 let mut n = start;
1708 loop {
1709 n = if n > 0 {
1710 n - 1
1711 } else {
1712 self.focus_flags.len() - 1
1713 };
1714 if matches!(
1715 self.navigable[n],
1716 Navigation::Reach
1717 | Navigation::ReachLeaveBack
1718 | Navigation::ReachLeaveFront
1719 | Navigation::Regular
1720 ) {
1721 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1722 return n;
1723 }
1724 if n == start {
1725 focus_debug!(self, " -> {}:end at start", n);
1726 return n;
1727 }
1728 }
1729 }
1730
1731 #[allow(clippy::type_complexity)]
1733 pub(super) fn clone_destruct(
1734 &self,
1735 ) -> (
1736 Vec<FocusFlag>,
1737 Vec<bool>,
1738 Vec<(Rect, u16)>,
1739 Vec<Navigation>,
1740 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1741 ) {
1742 (
1743 self.focus_flags.clone(),
1744 self.duplicate.clone(),
1745 self.areas.clone(),
1746 self.navigable.clone(),
1747 self.containers
1748 .iter()
1749 .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1750 .collect::<Vec<_>>(),
1751 )
1752 }
1753 }
1754
1755 #[cfg(test)]
1756 mod test {
1757 use crate::focus::core::FocusCore;
1758 use crate::{FocusBuilder, FocusFlag, HasFocus};
1759 use ratatui::layout::Rect;
1760
1761 #[test]
1762 fn test_change() {
1763 assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1764 assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1765
1766 assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1767 assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1768 assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1769 assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1770 assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1771
1772 assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1773 assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1774 assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1775 assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1776 assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1777
1778 assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1779 assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1780 assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1781 assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1782 assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1783
1784 assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1785 assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1786 assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1787 assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1788 assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1789 }
1790
1791 #[test]
1792 #[should_panic]
1793 fn test_double_insert() {
1794 let a = FocusFlag::named("a");
1795 let b = FocusFlag::named("b");
1796
1797 let mut fb = FocusBuilder::new(None);
1798 fb.widget(&a);
1799 fb.widget(&b);
1800 fb.widget(&a);
1801 fb.build();
1802 }
1803
1804 #[test]
1805 fn test_insert_remove() {
1806 let a = FocusFlag::named("a");
1807 let b = FocusFlag::named("b");
1808 let c = FocusFlag::named("c");
1809 let d = FocusFlag::named("d");
1810 let e = FocusFlag::named("e");
1811 let f = FocusFlag::named("f");
1812 let g = FocusFlag::named("g");
1813 let h = FocusFlag::named("h");
1814 let i = FocusFlag::named("i");
1815
1816 let mut fb = FocusBuilder::new(None);
1817 fb.widget(&a);
1818 fb.widget(&b);
1819 fb.widget(&c);
1820 let ff = fb.build();
1821 assert_eq!(ff.core.focus_flags[0], a);
1822 assert_eq!(ff.core.focus_flags[1], b);
1823 assert_eq!(ff.core.focus_flags[2], c);
1824
1825 let cc = FocusFlag::named("cc");
1826 let mut fb = FocusBuilder::new(None);
1827 fb.widget(&a);
1828 let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1829 fb.widget(&d);
1830 fb.widget(&e);
1831 fb.widget(&f);
1832 fb.end(cc_end);
1833 fb.widget(&b);
1834 fb.widget(&c);
1835 let mut ff = fb.build();
1836 assert_eq!(ff.core.focus_flags[0], a);
1837 assert_eq!(ff.core.focus_flags[1], d);
1838 assert_eq!(ff.core.focus_flags[2], e);
1839 assert_eq!(ff.core.focus_flags[3], f);
1840 assert_eq!(ff.core.focus_flags[4], b);
1841 assert_eq!(ff.core.focus_flags[5], c);
1842 assert_eq!(ff.core.containers[0].1, 1..4);
1843
1844 struct DD {
1845 dd: FocusFlag,
1846 g: FocusFlag,
1847 h: FocusFlag,
1848 i: FocusFlag,
1849 }
1850
1851 impl HasFocus for DD {
1852 fn build(&self, fb: &mut FocusBuilder) {
1853 let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1854 fb.widget(&self.g);
1855 fb.widget(&self.h);
1856 fb.widget(&self.i);
1857 fb.end(tag);
1858 }
1859
1860 fn focus(&self) -> FocusFlag {
1861 self.dd.clone()
1862 }
1863
1864 fn area(&self) -> Rect {
1865 Rect::default()
1866 }
1867 }
1868
1869 let dd = DD {
1870 dd: FocusFlag::named("dd"),
1871 g: g.clone(),
1872 h: h.clone(),
1873 i: i.clone(),
1874 };
1875 ff.replace_container(&cc, &dd);
1876 assert_eq!(ff.core.focus_flags[0], a);
1877 assert_eq!(ff.core.focus_flags[1], g);
1878 assert_eq!(ff.core.focus_flags[2], h);
1879 assert_eq!(ff.core.focus_flags[3], i);
1880 assert_eq!(ff.core.focus_flags[4], b);
1881 assert_eq!(ff.core.focus_flags[5], c);
1882 assert_eq!(ff.core.containers[0].1, 1..4);
1883 }
1884 }
1885}
1886
1887impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1888 #[inline(always)]
1889 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1890 match event {
1891 ct_event!(keycode press Tab) => {
1892 focus_debug!(
1893 self.core,
1894 "Tab {:?}",
1895 self.focused().map(|v| v.name().to_string())
1896 );
1897 let r = if self.next() {
1898 Outcome::Changed
1899 } else {
1900 Outcome::Continue
1901 };
1902 focus_debug!(
1903 self.core,
1904 " -> {:?}",
1905 self.focused().map(|v| v.name().to_string())
1906 );
1907 r
1908 }
1909 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1910 focus_debug!(
1911 self.core,
1912 "BackTab {:?}",
1913 self.focused().map(|v| v.name().to_string())
1914 );
1915 let r = if self.prev() {
1916 Outcome::Changed
1917 } else {
1918 Outcome::Continue
1919 };
1920 focus_debug!(
1921 self.core,
1922 " -> {:?}",
1923 self.focused().map(|v| v.name().to_string())
1924 );
1925 r
1926 }
1927 _ => self.handle(event, MouseOnly),
1928 }
1929 }
1930}
1931
1932impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1933 #[inline(always)]
1934 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1935 match event {
1936 ct_event!(mouse down Left for column, row) => {
1937 focus_debug!(self.core, "mouse down {},{}", column, row);
1938 if self.focus_at(*column, *row) {
1939 focus_debug!(
1940 self.core,
1941 " -> {:?}",
1942 self.focused().map(|v| v.name().to_string())
1943 );
1944 Outcome::Changed
1945 } else {
1946 self.reset_lost_gained();
1947 Outcome::Continue
1948 }
1949 }
1950 _ => {
1951 self.reset_lost_gained();
1952 Outcome::Continue
1953 }
1954 }
1955 }
1956}
1957
1958#[inline(always)]
1960pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1961 HandleEvent::handle(focus, event, Regular)
1962}