egui_charts/chart/selection/
mod.rs1use std::marker::PhantomData;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
20pub struct SeriesId(pub usize);
21
22impl SeriesId {
23 pub const MAIN: SeriesId = SeriesId(0);
25 pub const VOLUME: SeriesId = SeriesId(1);
27
28 pub fn name(&self) -> &'static str {
30 match self.0 {
31 0 => "Main Series",
32 1 => "Volume",
33 _ => "Series",
34 }
35 }
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
45pub enum ChartElementId {
46 Series(SeriesId),
48 OverlayIndicator(usize),
51 PaneIndicator(usize),
54}
55
56pub trait SelectableId: Copy + Eq + std::fmt::Debug {}
60
61impl<T: Copy + Eq + std::fmt::Debug> SelectableId for T {}
63
64#[derive(Clone, Debug)]
69pub struct SelectionState<Id: SelectableId> {
70 pub selected: Option<Id>,
72 pub hovered: Option<Id>,
74 pub bar_idx: Option<usize>,
76 _phantom: PhantomData<Id>,
77}
78
79impl<Id: SelectableId> Default for SelectionState<Id> {
80 fn default() -> Self {
81 Self {
82 selected: None,
83 hovered: None,
84 bar_idx: None,
85 _phantom: PhantomData,
86 }
87 }
88}
89
90impl<Id: SelectableId> SelectionState<Id> {
91 pub fn new() -> Self {
93 Self::default()
94 }
95
96 pub fn select(&mut self, id: Id, bar_idx: Option<usize>) {
98 self.selected = Some(id);
99 self.bar_idx = bar_idx;
100 }
101
102 pub fn deselect(&mut self) {
104 self.selected = None;
105 self.bar_idx = None;
106 }
107
108 pub fn set_hovered(&mut self, id: Option<Id>) {
110 self.hovered = id;
111 }
112
113 pub fn is_selected(&self, id: Id) -> bool {
115 self.selected == Some(id)
116 }
117
118 pub fn is_hovered(&self, id: Id) -> bool {
120 self.hovered == Some(id)
121 }
122
123 pub fn has_selection(&self) -> bool {
125 self.selected.is_some()
126 }
127
128 pub fn selected_id(&self) -> Option<Id> {
130 self.selected
131 }
132
133 pub fn selected_bar(&self) -> Option<usize> {
135 self.bar_idx
136 }
137
138 pub fn is_empty(&self) -> bool {
140 self.selected.is_none() && self.hovered.is_none()
141 }
142
143 pub fn clear(&mut self) {
145 self.selected = None;
146 self.hovered = None;
147 self.bar_idx = None;
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
156 struct TestId(usize);
157
158 #[test]
159 fn test_select_deselect() {
160 let mut state = SelectionState::<TestId>::new();
161 assert!(!state.has_selection());
162
163 state.select(TestId(1), Some(42));
164 assert!(state.has_selection());
165 assert!(state.is_selected(TestId(1)));
166 assert!(!state.is_selected(TestId(2)));
167 assert_eq!(state.selected_bar(), Some(42));
168
169 state.deselect();
170 assert!(!state.has_selection());
171 assert_eq!(state.selected_bar(), None);
172 }
173
174 #[test]
175 fn test_hover() {
176 let mut state = SelectionState::<TestId>::new();
177 assert!(!state.is_hovered(TestId(1)));
178
179 state.set_hovered(Some(TestId(1)));
180 assert!(state.is_hovered(TestId(1)));
181 assert!(!state.is_hovered(TestId(2)));
182
183 state.set_hovered(None);
184 assert!(!state.is_hovered(TestId(1)));
185 }
186
187 #[test]
188 fn test_chart_element_select_reselect_deselect() {
189 let mut state = SelectionState::<ChartElementId>::new();
192 assert!(!state.has_selection());
193
194 state.select(ChartElementId::PaneIndicator(2), Some(10));
196 assert_eq!(state.selected_id(), Some(ChartElementId::PaneIndicator(2)));
197 assert_eq!(state.selected_bar(), Some(10));
198
199 state.select(ChartElementId::Series(SeriesId::MAIN), Some(20));
201 assert_eq!(
202 state.selected_id(),
203 Some(ChartElementId::Series(SeriesId::MAIN))
204 );
205 assert!(!state.is_selected(ChartElementId::PaneIndicator(2)));
206 assert_eq!(state.selected_bar(), Some(20));
207
208 state.select(ChartElementId::OverlayIndicator(0), Some(5));
210 assert!(state.is_selected(ChartElementId::OverlayIndicator(0)));
211
212 state.deselect();
214 assert!(!state.has_selection());
215 assert_eq!(state.selected_id(), None);
216 assert_eq!(state.selected_bar(), None);
217 }
218
219 #[test]
220 fn test_chart_element_ids_are_distinct() {
221 let overlay = ChartElementId::OverlayIndicator(1);
224 let pane = ChartElementId::PaneIndicator(1);
225 let series = ChartElementId::Series(SeriesId(1));
226 assert_ne!(overlay, pane);
227 assert_ne!(overlay, series);
228 assert_ne!(pane, series);
229 }
230}