promkit_widgets/checkbox/
checkbox.rs1use std::{collections::HashSet, fmt};
2
3use promkit_core::grapheme::StyledGraphemes;
4
5use crate::listbox::Listbox;
6
7#[derive(Clone)]
13pub struct Checkbox {
14 listbox: Listbox,
15 picked: HashSet<usize>,
16}
17
18impl Checkbox {
19 pub fn from_displayable<E: fmt::Display, I: IntoIterator<Item = E>>(items: I) -> Self {
21 Self {
22 listbox: Listbox::from(items),
23 picked: HashSet::new(),
24 }
25 }
26
27 pub fn from_styled_graphemes(items: Vec<StyledGraphemes>) -> Self {
29 Self {
30 listbox: Listbox::from_styled_graphemes(items),
31 picked: HashSet::new(),
32 }
33 }
34
35 pub fn new_with_checked<T: fmt::Display, I: IntoIterator<Item = (T, bool)>>(iter: I) -> Self {
41 let (listbox, picked): (Vec<_>, Vec<_>) = iter
42 .into_iter()
43 .enumerate()
44 .map(|(index, (item, is_picked))| ((index, item), is_picked))
45 .unzip(); let listbox_items = listbox
48 .into_iter()
49 .map(|(_, item)| item)
50 .collect::<Vec<_>>();
51 let picked_indices = picked
52 .into_iter()
53 .enumerate()
54 .filter_map(
55 |(index, is_picked)| {
56 if is_picked { Some(index) } else { None }
57 },
58 )
59 .collect::<HashSet<usize>>();
60
61 Self {
62 listbox: Listbox::from(listbox_items),
63 picked: picked_indices,
64 }
65 }
66
67 pub fn items(&self) -> &Vec<StyledGraphemes> {
69 self.listbox.items()
70 }
71
72 pub fn position(&self) -> usize {
74 self.listbox.position()
75 }
76
77 pub fn picked_indexes(&self) -> &HashSet<usize> {
79 &self.picked
80 }
81
82 pub fn get(&self) -> Vec<StyledGraphemes> {
84 self.picked
85 .iter()
86 .fold(Vec::<StyledGraphemes>::new(), |mut ret, idx| {
87 ret.push(self.listbox.items().get(*idx).unwrap().to_owned());
88 ret
89 })
90 }
91
92 pub fn toggle(&mut self) {
94 if self.picked.contains(&self.listbox.position()) {
95 self.picked.remove(&self.listbox.position());
96 } else {
97 self.picked.insert(self.listbox.position());
98 }
99 }
100
101 pub fn backward(&mut self) -> bool {
104 self.listbox.backward()
105 }
106
107 pub fn forward(&mut self) -> bool {
110 self.listbox.forward()
111 }
112
113 pub fn move_to_head(&mut self) {
115 self.listbox.move_to_head()
116 }
117
118 pub fn move_to_tail(&mut self) {
120 self.listbox.move_to_tail()
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 mod new_with_checked {
129 use super::*;
130
131 #[test]
132 fn test() {
133 let items = vec![
135 (String::from("1"), true),
136 (String::from("2"), false),
137 (String::from("3"), true),
138 ];
139
140 let checkbox = Checkbox::new_with_checked(items);
142
143 assert_eq!(
145 checkbox.items(),
146 &vec![
147 StyledGraphemes::from("1"),
148 StyledGraphemes::from("2"),
149 StyledGraphemes::from("3"),
150 ]
151 );
152
153 let expected_picked_indexes: HashSet<usize> = [0, 2].iter().cloned().collect();
155 assert_eq!(checkbox.picked_indexes(), &expected_picked_indexes);
156 }
157 }
158}