Skip to main content

dear_imgui_rs/widget/multi_select/
storage.rs

1use std::collections::HashSet;
2
3/// Index-based selection storage for multi-select helpers.
4///
5/// Implement this trait for your selection container (e.g. `Vec<bool>`,
6/// `Vec<MyItem { selected: bool }>` or a custom type) to use
7/// [`crate::Ui::multi_select_indexed`].
8pub trait MultiSelectIndexStorage {
9    /// Total number of items in the selection scope.
10    fn len(&self) -> usize;
11
12    /// Returns `true` if the selection scope is empty.
13    fn is_empty(&self) -> bool {
14        self.len() == 0
15    }
16
17    /// Returns whether item at `index` is currently selected.
18    fn is_selected(&self, index: usize) -> bool;
19
20    /// Updates selection state for item at `index`.
21    fn set_selected(&mut self, index: usize, selected: bool);
22
23    /// Optional hint for current selection size.
24    ///
25    /// If provided, this is forwarded to `BeginMultiSelect()` to improve the
26    /// behavior of shortcuts such as `ImGuiMultiSelectFlags_ClearOnEscape`.
27    /// When `None` (default), the size is treated as "unknown".
28    fn selected_count_hint(&self) -> Option<usize> {
29        None
30    }
31}
32
33impl MultiSelectIndexStorage for Vec<bool> {
34    fn len(&self) -> usize {
35        self.len()
36    }
37
38    fn is_selected(&self, index: usize) -> bool {
39        self.get(index).copied().unwrap_or(false)
40    }
41
42    fn set_selected(&mut self, index: usize, selected: bool) {
43        if index < self.len() {
44            self[index] = selected;
45        }
46    }
47
48    fn selected_count_hint(&self) -> Option<usize> {
49        // For typical lists this is cheap enough; callers with large datasets
50        // can implement the trait manually with a more efficient counter.
51        Some(self.iter().filter(|&&b| b).count())
52    }
53}
54
55impl MultiSelectIndexStorage for &mut [bool] {
56    fn len(&self) -> usize {
57        (**self).len()
58    }
59
60    fn is_selected(&self, index: usize) -> bool {
61        self.get(index).copied().unwrap_or(false)
62    }
63
64    fn set_selected(&mut self, index: usize, selected: bool) {
65        if index < self.len() {
66            self[index] = selected;
67        }
68    }
69
70    fn selected_count_hint(&self) -> Option<usize> {
71        Some(self.iter().filter(|&&b| b).count())
72    }
73}
74
75/// Index-based selection storage backed by a key slice + `HashSet` of selected keys.
76///
77/// This is convenient when your application stores selection as a set of
78/// arbitrary keys (e.g. `HashSet<u32>` or `HashSet<MyId>`), but you still
79/// want to drive a multi-select scope using contiguous indices.
80pub struct KeySetSelection<'a, K>
81where
82    K: Eq + std::hash::Hash + Copy,
83{
84    keys: &'a [K],
85    selected: &'a mut HashSet<K>,
86}
87
88impl<'a, K> KeySetSelection<'a, K>
89where
90    K: Eq + std::hash::Hash + Copy,
91{
92    /// Create a new index-based view over a key slice and a selection set.
93    ///
94    /// - `keys`: stable index->key mapping (e.g. your backing array).
95    /// - `selected`: set of currently selected keys.
96    pub fn new(keys: &'a [K], selected: &'a mut HashSet<K>) -> Self {
97        Self { keys, selected }
98    }
99}
100
101impl<'a, K> MultiSelectIndexStorage for KeySetSelection<'a, K>
102where
103    K: Eq + std::hash::Hash + Copy,
104{
105    fn len(&self) -> usize {
106        self.keys.len()
107    }
108
109    fn is_selected(&self, index: usize) -> bool {
110        self.keys
111            .get(index)
112            .map(|k| self.selected.contains(k))
113            .unwrap_or(false)
114    }
115
116    fn set_selected(&mut self, index: usize, selected: bool) {
117        if let Some(&key) = self.keys.get(index) {
118            if selected {
119                self.selected.insert(key);
120            } else {
121                self.selected.remove(&key);
122            }
123        }
124    }
125
126    fn selected_count_hint(&self) -> Option<usize> {
127        Some(self.selected.len())
128    }
129}