1use std::collections::HashMap;
2
3pub trait FilterActiveItems<T> {
4 fn filter_active_items(&self) -> Vec<T>;
5}
6
7pub trait NavigateItems<T> {
8 fn navigate_first_item(&self) -> Option<T>;
9 fn navigate_last_item(&self) -> Option<T>;
10 fn navigate_next_item(&self) -> Option<T>;
11 fn navigate_previous_item(&self) -> Option<T>;
12}
13
14pub trait Toggle {
15 fn toggle(&self);
16
17 fn open(&self);
18
19 fn close(&self);
20}
21
22pub trait Focus {
23 fn focus(&self) -> bool;
25}
26
27pub trait GetIndex<T> {
28 fn get_index(&self) -> T;
29}
30
31pub trait ManageFocus {
32 fn set_focus(&self, index: Option<usize>);
33
34 fn item_in_focus(&self, index: usize) -> bool;
36}
37
38pub trait IsActive {
39 fn is_active(&self) -> bool;
40}
41
42pub fn filter_active<T>(items: HashMap<usize, T>) -> Vec<T>
43where
44 T: GetIndex<usize> + IsActive + Clone,
45{
46 let mut items = items
47 .values()
48 .filter(|item| item.is_active())
49 .cloned()
50 .collect::<Vec<T>>();
51
52 items.sort_by(|a, b| a.get_index().cmp(&b.get_index()));
53
54 items
55}
56
57pub fn next_item<T>(items: Vec<T>, current_focus: Option<usize>, allow_loop: bool) -> Option<T>
59where
60 T: GetIndex<usize> + Clone,
61{
62 let Some(item_focus) = current_focus else {
63 if let Some(first) = items.get(0) {
64 return Some(first.clone());
65 }
66 return None;
67 };
68
69 let Some(current_pos) = items.iter().position(|item| item.get_index() == item_focus) else {
70 return None;
71 };
72
73 items.get(current_pos + 1).cloned().or_else(|| {
74 if allow_loop {
75 items.get(0).cloned()
76 } else {
77 None
78 }
79 })
80}
81
82pub fn previous_item<T>(items: Vec<T>, current_focus: Option<usize>, allow_loop: bool) -> Option<T>
84where
85 T: GetIndex<usize> + Clone,
86{
87 let Some(item_focus) = current_focus else {
88 if let Some(last) = items.last() {
89 return Some(last.clone());
90 }
91 return None;
92 };
93
94 let Some(current_pos) = items.iter().position(|item| item.get_index() == item_focus) else {
95 return None;
96 };
97
98 if current_pos == 0 {
99 if allow_loop {
100 return items.last().cloned();
101 }
102 return None;
103 }
104
105 items.get(current_pos - 1).cloned()
106}