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