biji_ui/
items.rs

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    /// Focus on element
24    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    /// Check if item is in focus
35    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
57/// Get next item in items list. If current_focus is None, return first item if `allow_loop` is `true`.
58pub 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
82/// Get previous item in items list. If current_focus is None, return last item.
83pub 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}