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())
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 if !matches!(navigable, Navigation::Mouse | Navigation::None) {
955 focus_debug!(self, "{:#?}", self);
956 panic!(
957 "Duplicate flag is only allowed if the second call uses Navigation::Mouse|Navigation::None. Was {:?}.",
958 focus
959 )
960 }
961 }
962
963 focus_debug!(self, "widget {:?}", focus);
964
965 self.focus_ids.insert(focus.widget_id());
966 self.focus_flags.push(focus);
967 self.duplicate.push(duplicate);
968 self.areas.push((area, self.z_base + area_z));
969 self.navigable.push(navigable);
970 }
971
972 #[must_use]
981 pub fn start_with_flags(
982 &mut self,
983 container_flag: FocusFlag,
984 area: Rect,
985 area_z: u16,
986 ) -> FocusFlag {
987 focus_debug!(self, "start container {:?}", container_flag);
988
989 assert!(!self.container_ids.contains(&container_flag.widget_id()));
991
992 self.z_base += area_z;
993
994 let len = self.focus_flags.len();
995 self.container_ids.insert(container_flag.widget_id());
996 self.containers.push((
997 Container {
998 container_flag: container_flag.clone(),
999 area: (area, self.z_base),
1000 delta_z: area_z,
1001 complete: false,
1002 },
1003 len..len,
1004 ));
1005
1006 container_flag
1007 }
1008
1009 pub fn build(mut self) -> Focus {
1015 for v in &self.last.focus_flags {
1017 if !self.focus_ids.contains(&v.widget_id()) {
1018 v.clear();
1019 }
1020 }
1021 for (v, _) in &self.last.containers {
1022 let have_container = self
1023 .containers
1024 .iter()
1025 .any(|(c, _)| v.container_flag == c.container_flag);
1026 if !have_container {
1027 v.container_flag.clear();
1028 }
1029 }
1030 self.last.clear();
1031
1032 for (c, _) in self.containers.iter_mut().rev() {
1034 if !c.complete {
1035 panic!("FocusBuilder: Unclosed container {:?}", c.container_flag);
1036 }
1037 }
1038
1039 let log = self.last.log.get();
1040 let insta_panic = self.last.insta_panic.get();
1041
1042 Focus {
1043 last: self.last,
1044 core: FocusCore {
1045 log: Cell::new(log),
1046 insta_panic: Cell::new(insta_panic),
1047 focus_ids: self.focus_ids,
1048 focus_flags: self.focus_flags,
1049 duplicate: self.duplicate,
1050 areas: self.areas,
1051 navigable: self.navigable,
1052 container_ids: self.container_ids,
1053 containers: self.containers,
1054 },
1055 }
1056 }
1057 }
1058
1059 #[derive(Debug, Clone)]
1061 struct Container {
1062 container_flag: FocusFlag,
1066 area: (Rect, u16),
1069 delta_z: u16,
1071 complete: bool,
1073 }
1074
1075 #[derive(Debug, Default, Clone)]
1077 pub(super) struct FocusCore {
1078 pub(super) log: Cell<bool>,
1080 pub(super) insta_panic: Cell<bool>,
1081
1082 focus_ids: HashSet<usize, FxBuildHasher>,
1084 focus_flags: Vec<FocusFlag>,
1086 duplicate: Vec<bool>,
1089 areas: Vec<(Rect, u16)>,
1092 navigable: Vec<Navigation>,
1095 container_ids: HashSet<usize, FxBuildHasher>,
1097 containers: Vec<(Container, Range<usize>)>,
1102 }
1103
1104 impl FocusCore {
1105 pub(super) fn clear(&mut self) {
1107 self.focus_ids.clear();
1108 self.focus_flags.clear();
1109 self.duplicate.clear();
1110 self.areas.clear();
1111 self.navigable.clear();
1112 self.container_ids.clear();
1113 self.containers.clear();
1114 }
1115
1116 pub(super) fn find_widget_id(&self, widget_id: usize) -> Option<FocusFlag> {
1118 self.focus_flags
1119 .iter()
1120 .find(|v| widget_id == v.widget_id())
1121 .cloned()
1122 }
1123
1124 pub(super) fn is_widget(&self, focus_flag: &FocusFlag) -> bool {
1126 self.focus_ids.contains(&focus_flag.widget_id())
1127 }
1128
1129 pub(super) fn index_of(&self, focus_flag: &FocusFlag) -> Option<usize> {
1131 self.focus_flags
1132 .iter()
1133 .enumerate()
1134 .find(|(_, f)| *f == focus_flag)
1135 .map(|(idx, _)| idx)
1136 }
1137
1138 pub(super) fn is_container(&self, focus_flag: &FocusFlag) -> bool {
1140 self.container_ids.contains(&focus_flag.widget_id())
1141 }
1142
1143 pub(super) fn container_index_of(
1145 &self,
1146 container_flag: &FocusFlag,
1147 ) -> Option<(usize, Range<usize>)> {
1148 self.containers
1149 .iter()
1150 .enumerate()
1151 .find(|(_, (c, _))| &c.container_flag == container_flag)
1152 .map(|(idx, (_, range))| (idx, range.clone()))
1153 }
1154
1155 pub(super) fn insert_container(
1160 &mut self,
1161 idx: usize,
1162 cidx: usize,
1163 mut container: FocusCore,
1164 ) {
1165 for c in &self.focus_flags {
1166 for d in &container.focus_flags {
1167 assert_ne!(c, d);
1168 }
1169 }
1170
1171 let start = idx;
1173 let end = idx + container.focus_flags.len();
1174
1175 self.focus_ids.extend(container.focus_ids.iter());
1176 self.focus_flags
1177 .splice(idx..idx, container.focus_flags.drain(..));
1178 self.duplicate
1179 .splice(idx..idx, container.duplicate.drain(..));
1180 self.areas.splice(idx..idx, container.areas.drain(..));
1181 self.navigable
1182 .splice(idx..idx, container.navigable.drain(..));
1183
1184 for (_, r) in &mut self.containers {
1186 *r = Self::expand(start..end, r.clone());
1187 }
1188 self.containers.splice(
1190 cidx..cidx,
1191 container
1192 .containers
1193 .drain(..)
1194 .map(|(c, r)| (c, Self::shift(start, r))),
1195 );
1196 self.container_ids.extend(container.container_ids.iter());
1197 }
1198
1199 pub(super) fn remove_container(&mut self, cidx: usize) -> FocusCore {
1202 let crange = self.containers[cidx].1.clone();
1203
1204 let focus_flags = self.focus_flags.drain(crange.clone()).collect::<Vec<_>>();
1206 let mut focus_ids = HashSet::<_, FxBuildHasher>::default();
1207 for f in focus_flags.iter() {
1208 self.focus_ids.remove(&f.widget_id());
1209 focus_ids.insert(f.widget_id());
1210 }
1211 let duplicate = self.duplicate.drain(crange.clone()).collect::<Vec<_>>();
1212 let areas = self.areas.drain(crange.clone()).collect::<Vec<_>>();
1213 let navigable = self.navigable.drain(crange.clone()).collect::<Vec<_>>();
1214 let sub_containers = self
1215 .containers
1216 .iter()
1217 .filter(|(_, r)| r.start >= crange.start && r.end <= crange.end)
1218 .cloned()
1219 .collect::<Vec<_>>();
1220 self.containers
1222 .retain(|(_, r)| !(r.start >= crange.start && r.end <= crange.end));
1223 let mut sub_container_ids: HashSet<usize, FxBuildHasher> = HashSet::default();
1224 for (sc, _) in sub_containers.iter() {
1225 self.container_ids.remove(&sc.container_flag.widget_id());
1226 sub_container_ids.insert(sc.container_flag.widget_id());
1227 }
1228
1229 for (_, r) in &mut self.containers {
1231 *r = Self::shrink(crange.start..crange.end, r.clone());
1232 }
1233
1234 FocusCore {
1235 log: Cell::new(false),
1236 insta_panic: Cell::new(false),
1237 focus_ids,
1238 focus_flags,
1239 duplicate,
1240 areas,
1241 navigable,
1242 container_ids: sub_container_ids,
1243 containers: sub_containers,
1244 }
1245 }
1246
1247 fn shift(n: usize, range: Range<usize>) -> Range<usize> {
1249 range.start + n..range.end + n
1250 }
1251
1252 fn expand(insert: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1254 let len = insert.end - insert.start;
1255
1256 if range.start >= insert.start {
1257 range.start += len;
1258 }
1259 if range.end > insert.start {
1260 range.end += len;
1261 }
1262 range
1263 }
1264
1265 fn shrink(remove: Range<usize>, mut range: Range<usize>) -> Range<usize> {
1267 let len = remove.end - remove.start;
1268
1269 if range.start < remove.start {
1270 } else if range.start >= remove.start && range.start <= remove.end {
1272 range.start = remove.start;
1273 } else {
1274 range.start -= len;
1275 }
1276
1277 if range.end < remove.start {
1278 } else if range.end >= remove.start && range.end <= remove.end {
1280 range.end = remove.start;
1281 } else {
1282 range.end -= len;
1283 }
1284
1285 range
1286 }
1287
1288 fn __start_change(&self, set_lost: bool) {
1291 for (f, duplicate) in self.focus_flags.iter().zip(self.duplicate.iter()) {
1292 if *duplicate {
1293 continue;
1295 }
1296 if set_lost {
1297 f.set_lost(f.get());
1298 } else {
1299 f.set_lost(false);
1300 }
1301 f.set_gained(false);
1302 f.set(false);
1303 }
1304 }
1305
1306 fn __focus(&self, n: usize, set_lost: bool) -> bool {
1309 if let Some(f) = self.focus_flags.get(n) {
1310 focus_debug!(self, " -> focus {}:{:?}", n, f.name());
1311 f.set(true);
1312 if set_lost {
1313 if f.lost() {
1314 f.set_lost(false);
1317 f.set_gained(false);
1318 false
1319 } else {
1320 f.set_gained(true);
1321 true
1322 }
1323 } else {
1324 false
1325 }
1326 } else {
1327 false
1328 }
1329 }
1330
1331 #[allow(clippy::collapsible_if)]
1333 fn __accumulate(&self) {
1334 for (n, f) in self.focus_flags.iter().enumerate() {
1335 if f.gained() && !self.duplicate[n] {
1336 if let Some(on_gained_cb) = f.0.on_gained.borrow().as_ref() {
1337 focus_debug!(self, " -> notify_on_gained {}:{:?}", n, f.name());
1338 on_gained_cb();
1339 }
1340 }
1341 if f.lost() && !self.duplicate[n] {
1342 if let Some(on_lost_cb) = f.0.on_lost.borrow().as_ref() {
1343 focus_debug!(self, " -> notify_on_lost {}:{:?}", n, f.name());
1344 on_lost_cb();
1345 }
1346 }
1347 }
1348
1349 for (f, r) in &self.containers {
1350 let mut any_gained = false;
1351 let mut any_lost = false;
1352 let mut any_focused = false;
1353
1354 for idx in r.clone() {
1355 any_gained |= self.focus_flags[idx].gained();
1356 any_lost |= self.focus_flags[idx].lost();
1357 any_focused |= self.focus_flags[idx].get();
1358 }
1359
1360 f.container_flag.set(any_focused);
1361 f.container_flag.set_lost(any_lost && !any_gained);
1362 if any_lost && !any_gained {
1363 if let Some(on_lost_cb) = f.container_flag.0.on_lost.borrow().as_ref() {
1364 focus_debug!(
1365 self,
1366 "-> notify_on_lost container {:?}",
1367 f.container_flag.name()
1368 );
1369 on_lost_cb();
1370 }
1371 }
1372 f.container_flag.set_gained(any_gained && !any_lost);
1373 if any_gained && !any_lost {
1374 if let Some(on_gained_cb) = f.container_flag.0.on_gained.borrow().as_ref() {
1375 focus_debug!(
1376 self,
1377 "-> notify_on_gained container {:?}",
1378 f.container_flag.name()
1379 );
1380 on_gained_cb();
1381 }
1382 }
1383 }
1384 }
1385
1386 pub(super) fn reset(&self) {
1388 for f in self.focus_flags.iter() {
1389 f.set(false);
1390 f.set_lost(false);
1391 f.set_gained(false);
1392 }
1393 for (f, _) in self.containers.iter() {
1394 f.container_flag.set(false);
1395 f.container_flag.set_gained(false);
1396 f.container_flag.set_lost(false);
1397 }
1398 }
1399
1400 pub(super) fn reset_lost_gained(&self) {
1402 for f in self.focus_flags.iter() {
1403 f.set_lost(false);
1404 f.set_gained(false);
1405 }
1406 for (f, _) in self.containers.iter() {
1407 f.container_flag.set_gained(false);
1408 f.container_flag.set_lost(false);
1409 }
1410 }
1411
1412 pub(super) fn first(&self) {
1414 if let Some(n) = self.first_navigable(0) {
1415 self.__start_change(true);
1416 self.__focus(n, true);
1417 self.__accumulate();
1418 } else {
1419 focus_debug!(self, " -> no navigable widget");
1420 }
1421 }
1422
1423 pub(super) fn none(&self) {
1425 self.__start_change(true);
1426 self.__accumulate();
1427 }
1428
1429 pub(super) fn first_container(&self, container: &FocusFlag) {
1431 if let Some((_idx, range)) = self.container_index_of(container) {
1432 if let Some(n) = self.first_navigable(range.start) {
1433 if n < range.end {
1434 self.__start_change(true);
1435 self.__focus(n, true);
1436 self.__accumulate();
1437 } else {
1438 focus_debug!(self, " -> no navigable widget for container");
1439 }
1440 } else {
1441 focus_debug!(self, " -> no navigable widget");
1442 }
1443 } else {
1444 focus_fail!(self, " => container not found");
1445 }
1446 }
1447
1448 pub(super) fn focus_idx(&self, n: usize, set_lost: bool) {
1450 self.__start_change(set_lost);
1451 self.__focus(n, set_lost);
1452 self.__accumulate();
1453 }
1454
1455 pub(super) fn focus_at(&self, col: u16, row: u16) -> bool {
1459 let pos = (col, row).into();
1460
1461 enum ZOrder {
1462 Widget(usize),
1463 Container(usize),
1464 }
1465
1466 let mut z_order: Option<(ZOrder, u16)> = None;
1468 for (idx, (sub, _)) in self.containers.iter().enumerate() {
1471 if sub.area.0.contains(pos) {
1472 focus_debug!(
1473 self,
1474 " container area-match {:?}",
1475 sub.container_flag.name()
1476 );
1477
1478 z_order = if let Some(zz) = z_order {
1479 if zz.1 <= sub.area.1 {
1480 Some((ZOrder::Container(idx), sub.area.1))
1481 } else {
1482 Some(zz)
1483 }
1484 } else {
1485 Some((ZOrder::Container(idx), sub.area.1))
1486 };
1487 }
1488 }
1489 for (idx, area) in self.areas.iter().enumerate() {
1491 if area.0.contains(pos) {
1492 focus_debug!(self, " area-match {:?}", self.focus_flags[idx].name());
1493
1494 z_order = if let Some(zz) = z_order {
1495 if zz.1 <= area.1 {
1496 Some((ZOrder::Widget(idx), area.1))
1497 } else {
1498 Some(zz)
1499 }
1500 } else {
1501 Some((ZOrder::Widget(idx), area.1))
1502 };
1503 }
1504 }
1505
1506 if let Some((idx, _)) = z_order {
1508 match idx {
1509 ZOrder::Widget(idx) => {
1510 if self.navigable[idx] != Navigation::None {
1511 self.__start_change(true);
1512 let r = self.__focus(idx, true);
1513 self.__accumulate();
1514 return r;
1515 } else {
1516 focus_debug!(
1517 self,
1518 " -> not mouse reachable {:?}",
1519 self.focus_flags[idx].name()
1520 );
1521 return false;
1522 }
1523 }
1524 ZOrder::Container(idx) => {
1525 let range = &self.containers[idx].1;
1526 if let Some(n) = self.first_navigable(range.start) {
1527 self.__start_change(true);
1528 let r = self.__focus(n, true);
1529 self.__accumulate();
1530 return r;
1531 }
1532 }
1533 }
1534 }
1535
1536 focus_debug!(self, " -> no widget at pos");
1538
1539 false
1540 }
1541
1542 pub(super) fn expel_container(&self, flag: FocusFlag) -> bool {
1544 if let Some((_idx, range)) = self.container_index_of(&flag) {
1545 self.__start_change(true);
1546 let n = self.next_navigable(range.end);
1547 self.__focus(n, true);
1548 self.__accumulate();
1549
1550 if flag.is_focused() {
1552 focus_debug!(self, " -> focus not usable. cleared");
1553 self.none();
1554 } else {
1555 focus_debug!(self, " -> expelled.");
1556 }
1557 true
1558 } else {
1559 focus_fail!(self, " => container not found");
1560 false
1561 }
1562 }
1563
1564 pub(super) fn next(&self) -> bool {
1566 self.__start_change(true);
1567 for (n, p) in self.focus_flags.iter().enumerate() {
1568 if p.lost() {
1569 let n = self.next_navigable(n);
1570 self.__focus(n, true);
1571 self.__accumulate();
1572 return true;
1573 }
1574 }
1575 if let Some(n) = self.first_navigable(0) {
1576 focus_debug!(
1577 self,
1578 " use first_navigable {}:{:?}",
1579 n,
1580 self.focus_flags[n].name()
1581 );
1582 self.__focus(n, true);
1583 self.__accumulate();
1584 return true;
1585 }
1586 focus_debug!(self, " -> no next");
1587 false
1588 }
1589
1590 pub(super) fn prev(&self) -> bool {
1592 self.__start_change(true);
1593 for (i, p) in self.focus_flags.iter().enumerate() {
1594 if p.lost() {
1595 let n = self.prev_navigable(i);
1596 self.__focus(n, true);
1597 self.__accumulate();
1598 return true;
1599 }
1600 }
1601 if let Some(n) = self.first_navigable(0) {
1602 focus_debug!(
1603 self,
1604 " use first_navigable {}:{:?}",
1605 n,
1606 self.focus_flags[n].name()
1607 );
1608 self.__focus(n, true);
1609 self.__accumulate();
1610 return true;
1611 }
1612 focus_debug!(self, " -> no prev");
1613 false
1614 }
1615
1616 pub(super) fn navigation(&self) -> Option<Navigation> {
1618 self.focus_flags
1619 .iter()
1620 .enumerate()
1621 .find(|(_, v)| v.get())
1622 .map(|(i, _)| self.navigable[i])
1623 }
1624
1625 pub(super) fn focused(&self) -> Option<FocusFlag> {
1627 self.focus_flags.iter().find(|v| v.get()).cloned()
1628 }
1629
1630 pub(super) fn lost_focus(&self) -> Option<FocusFlag> {
1632 self.focus_flags.iter().find(|v| v.lost()).cloned()
1633 }
1634
1635 pub(super) fn gained_focus(&self) -> Option<FocusFlag> {
1637 self.focus_flags.iter().find(|v| v.gained()).cloned()
1638 }
1639
1640 fn first_navigable(&self, start: usize) -> Option<usize> {
1642 focus_debug!(
1643 self,
1644 "first navigable, start at {}:{:?} ",
1645 start,
1646 if start < self.focus_flags.len() {
1647 self.focus_flags[start].name()
1648 } else {
1649 "beginning".into()
1650 }
1651 );
1652 for n in start..self.focus_flags.len() {
1653 if matches!(
1654 self.navigable[n],
1655 Navigation::Reach
1656 | Navigation::ReachLeaveBack
1657 | Navigation::ReachLeaveFront
1658 | Navigation::Regular
1659 ) {
1660 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1661 return Some(n);
1662 }
1663 }
1664 focus_debug!(self, " -> no first");
1665 None
1666 }
1667
1668 fn next_navigable(&self, start: usize) -> usize {
1670 focus_debug!(
1671 self,
1672 "next navigable after {}:{:?}",
1673 start,
1674 if start < self.focus_flags.len() {
1675 self.focus_flags[start].name()
1676 } else {
1677 "last".into()
1678 }
1679 );
1680
1681 let mut n = start;
1682 loop {
1683 n = if n + 1 < self.focus_flags.len() {
1684 n + 1
1685 } else {
1686 0
1687 };
1688 if matches!(
1689 self.navigable[n],
1690 Navigation::Reach
1691 | Navigation::ReachLeaveBack
1692 | Navigation::ReachLeaveFront
1693 | Navigation::Regular
1694 ) {
1695 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1696 return n;
1697 }
1698 if n == start {
1699 focus_debug!(self, " -> {}:end at start", n);
1700 return n;
1701 }
1702 }
1703 }
1704
1705 fn prev_navigable(&self, start: usize) -> usize {
1707 focus_debug!(
1708 self,
1709 "prev navigable before {}:{:?}",
1710 start,
1711 self.focus_flags[start].name()
1712 );
1713
1714 let mut n = start;
1715 loop {
1716 n = if n > 0 {
1717 n - 1
1718 } else {
1719 self.focus_flags.len() - 1
1720 };
1721 if matches!(
1722 self.navigable[n],
1723 Navigation::Reach
1724 | Navigation::ReachLeaveBack
1725 | Navigation::ReachLeaveFront
1726 | Navigation::Regular
1727 ) {
1728 focus_debug!(self, " -> {}:{:?}", n, self.focus_flags[n].name());
1729 return n;
1730 }
1731 if n == start {
1732 focus_debug!(self, " -> {}:end at start", n);
1733 return n;
1734 }
1735 }
1736 }
1737
1738 #[allow(clippy::type_complexity)]
1740 pub(super) fn clone_destruct(
1741 &self,
1742 ) -> (
1743 Vec<FocusFlag>,
1744 Vec<bool>,
1745 Vec<(Rect, u16)>,
1746 Vec<Navigation>,
1747 Vec<(FocusFlag, (Rect, u16), Range<usize>)>,
1748 ) {
1749 (
1750 self.focus_flags.clone(),
1751 self.duplicate.clone(),
1752 self.areas.clone(),
1753 self.navigable.clone(),
1754 self.containers
1755 .iter()
1756 .map(|(v, w)| (v.container_flag.clone(), v.area, w.clone()))
1757 .collect::<Vec<_>>(),
1758 )
1759 }
1760 }
1761
1762 #[cfg(test)]
1763 mod test {
1764 use crate::focus::core::FocusCore;
1765 use crate::{FocusBuilder, FocusFlag, HasFocus};
1766 use ratatui::layout::Rect;
1767
1768 #[test]
1769 fn test_change() {
1770 assert_eq!(FocusCore::shift(0, 1..1), 1..1);
1771 assert_eq!(FocusCore::shift(1, 1..1), 2..2);
1772
1773 assert_eq!(FocusCore::expand(3..4, 0..1), 0..1);
1774 assert_eq!(FocusCore::expand(3..4, 1..2), 1..2);
1775 assert_eq!(FocusCore::expand(3..4, 2..3), 2..3);
1776 assert_eq!(FocusCore::expand(3..4, 3..4), 4..5);
1777 assert_eq!(FocusCore::expand(3..4, 4..5), 5..6);
1778
1779 assert_eq!(FocusCore::expand(3..3, 0..1), 0..1);
1780 assert_eq!(FocusCore::expand(3..3, 1..2), 1..2);
1781 assert_eq!(FocusCore::expand(3..3, 2..3), 2..3);
1782 assert_eq!(FocusCore::expand(3..3, 3..4), 3..4);
1783 assert_eq!(FocusCore::expand(3..3, 4..5), 4..5);
1784
1785 assert_eq!(FocusCore::shrink(3..4, 0..1), 0..1);
1786 assert_eq!(FocusCore::shrink(3..4, 2..3), 2..3);
1787 assert_eq!(FocusCore::shrink(3..4, 3..4), 3..3);
1788 assert_eq!(FocusCore::shrink(3..4, 4..5), 3..4);
1789 assert_eq!(FocusCore::shrink(3..4, 5..6), 4..5);
1790
1791 assert_eq!(FocusCore::shrink(3..3, 0..1), 0..1);
1792 assert_eq!(FocusCore::shrink(3..3, 1..2), 1..2);
1793 assert_eq!(FocusCore::shrink(3..3, 2..3), 2..3);
1794 assert_eq!(FocusCore::shrink(3..3, 3..4), 3..4);
1795 assert_eq!(FocusCore::shrink(3..3, 4..5), 4..5);
1796 }
1797
1798 #[test]
1799 #[should_panic]
1800 fn test_double_insert() {
1801 let a = FocusFlag::named("a");
1802 let b = FocusFlag::named("b");
1803
1804 let mut fb = FocusBuilder::new(None);
1805 fb.widget(&a);
1806 fb.widget(&b);
1807 fb.widget(&a);
1808 fb.build();
1809 }
1810
1811 #[test]
1812 fn test_insert_remove() {
1813 let a = FocusFlag::named("a");
1814 let b = FocusFlag::named("b");
1815 let c = FocusFlag::named("c");
1816 let d = FocusFlag::named("d");
1817 let e = FocusFlag::named("e");
1818 let f = FocusFlag::named("f");
1819 let g = FocusFlag::named("g");
1820 let h = FocusFlag::named("h");
1821 let i = FocusFlag::named("i");
1822
1823 let mut fb = FocusBuilder::new(None);
1824 fb.widget(&a);
1825 fb.widget(&b);
1826 fb.widget(&c);
1827 let ff = fb.build();
1828 assert_eq!(ff.core.focus_flags[0], a);
1829 assert_eq!(ff.core.focus_flags[1], b);
1830 assert_eq!(ff.core.focus_flags[2], c);
1831
1832 let cc = FocusFlag::named("cc");
1833 let mut fb = FocusBuilder::new(None);
1834 fb.widget(&a);
1835 let cc_end = fb.start_with_flags(cc.clone(), Rect::default(), 0);
1836 fb.widget(&d);
1837 fb.widget(&e);
1838 fb.widget(&f);
1839 fb.end(cc_end);
1840 fb.widget(&b);
1841 fb.widget(&c);
1842 let mut ff = fb.build();
1843 assert_eq!(ff.core.focus_flags[0], a);
1844 assert_eq!(ff.core.focus_flags[1], d);
1845 assert_eq!(ff.core.focus_flags[2], e);
1846 assert_eq!(ff.core.focus_flags[3], f);
1847 assert_eq!(ff.core.focus_flags[4], b);
1848 assert_eq!(ff.core.focus_flags[5], c);
1849 assert_eq!(ff.core.containers[0].1, 1..4);
1850
1851 struct DD {
1852 dd: FocusFlag,
1853 g: FocusFlag,
1854 h: FocusFlag,
1855 i: FocusFlag,
1856 }
1857
1858 impl HasFocus for DD {
1859 fn build(&self, fb: &mut FocusBuilder) {
1860 let tag = fb.start_with_flags(self.dd.clone(), self.area(), self.area_z());
1861 fb.widget(&self.g);
1862 fb.widget(&self.h);
1863 fb.widget(&self.i);
1864 fb.end(tag);
1865 }
1866
1867 fn focus(&self) -> FocusFlag {
1868 self.dd.clone()
1869 }
1870
1871 fn area(&self) -> Rect {
1872 Rect::default()
1873 }
1874 }
1875
1876 let dd = DD {
1877 dd: FocusFlag::named("dd"),
1878 g: g.clone(),
1879 h: h.clone(),
1880 i: i.clone(),
1881 };
1882 ff.replace_container(&cc, &dd);
1883 assert_eq!(ff.core.focus_flags[0], a);
1884 assert_eq!(ff.core.focus_flags[1], g);
1885 assert_eq!(ff.core.focus_flags[2], h);
1886 assert_eq!(ff.core.focus_flags[3], i);
1887 assert_eq!(ff.core.focus_flags[4], b);
1888 assert_eq!(ff.core.focus_flags[5], c);
1889 assert_eq!(ff.core.containers[0].1, 1..4);
1890 }
1891 }
1892}
1893
1894impl HandleEvent<crossterm::event::Event, Regular, Outcome> for Focus {
1895 #[inline(always)]
1896 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> Outcome {
1897 match event {
1898 ct_event!(keycode press Tab) => {
1899 focus_debug!(
1900 self.core,
1901 "Tab {:?}",
1902 self.focused().map(|v| v.name().to_string())
1903 );
1904 let r = if self.next() {
1905 Outcome::Changed
1906 } else {
1907 Outcome::Continue
1908 };
1909 focus_debug!(
1910 self.core,
1911 " -> {:?} {:?}",
1912 r,
1913 self.focused().map(|v| v.name().to_string())
1914 );
1915 r
1916 }
1917 ct_event!(keycode press SHIFT-Tab) | ct_event!(keycode press SHIFT-BackTab) => {
1918 focus_debug!(
1919 self.core,
1920 "BackTab {:?}",
1921 self.focused().map(|v| v.name().to_string())
1922 );
1923 let r = if self.prev() {
1924 Outcome::Changed
1925 } else {
1926 Outcome::Continue
1927 };
1928 focus_debug!(
1929 self.core,
1930 " -> {:?} {:?}",
1931 r,
1932 self.focused().map(|v| v.name().to_string())
1933 );
1934 r
1935 }
1936 _ => self.handle(event, MouseOnly),
1937 }
1938 }
1939}
1940
1941impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for Focus {
1942 #[inline(always)]
1943 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> Outcome {
1944 match event {
1945 ct_event!(mouse down Left for column, row) => {
1946 focus_debug!(self.core, "mouse down {},{}", column, row);
1947 if self.focus_at(*column, *row) {
1948 focus_debug!(
1949 self.core,
1950 " -> {:?}",
1951 self.focused().map(|v| v.name().to_string())
1952 );
1953 Outcome::Changed
1954 } else {
1955 self.reset_lost_gained();
1956 Outcome::Continue
1957 }
1958 }
1959 _ => {
1960 self.reset_lost_gained();
1961 Outcome::Continue
1962 }
1963 }
1964 }
1965}
1966
1967#[inline(always)]
1969pub fn handle_focus(focus: &mut Focus, event: &crossterm::event::Event) -> Outcome {
1970 HandleEvent::handle(focus, event, Regular)
1971}