Skip to main content

embedded_gui/
state.rs

1#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2pub struct ListState {
3    pub selected: usize,
4    pub offset: usize,
5    pub visible_rows: usize,
6}
7
8impl ListState {
9    pub const fn new(selected: usize, offset: usize, visible_rows: usize) -> Self {
10        Self {
11            selected,
12            offset,
13            visible_rows,
14        }
15    }
16
17    pub fn set_selected(&mut self, selected: usize, len: usize) -> bool {
18        let next = selected.min(len.saturating_sub(1));
19        let changed = next != self.selected;
20        self.selected = next;
21        self.keep_selected_visible();
22        changed
23    }
24
25    pub fn next(&mut self, len: usize) -> bool {
26        self.bump(len, 1)
27    }
28
29    pub fn previous(&mut self, len: usize) -> bool {
30        self.bump(len, -1)
31    }
32
33    pub fn bump(&mut self, len: usize, delta: i8) -> bool {
34        if len == 0 {
35            return false;
36        }
37        let next = if delta >= 0 {
38            (self.selected + 1) % len
39        } else if self.selected == 0 {
40            len - 1
41        } else {
42            self.selected - 1
43        };
44        self.set_selected(next, len)
45    }
46
47    pub fn keep_selected_visible(&mut self) {
48        let rows = self.visible_rows.max(1);
49        if self.selected < self.offset {
50            self.offset = self.selected;
51        } else if self.selected >= self.offset.saturating_add(rows) {
52            self.offset = self.selected.saturating_add(1).saturating_sub(rows);
53        }
54    }
55}
56
57#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
58pub struct TabsState {
59    pub selected: usize,
60}
61
62impl TabsState {
63    pub const fn new(selected: usize) -> Self {
64        Self { selected }
65    }
66
67    pub fn set_selected(&mut self, selected: usize, len: usize) -> bool {
68        let next = selected.min(len.saturating_sub(1));
69        let changed = next != self.selected;
70        self.selected = next;
71        changed
72    }
73
74    pub fn next(&mut self, len: usize) -> bool {
75        self.bump(len, 1)
76    }
77
78    pub fn previous(&mut self, len: usize) -> bool {
79        self.bump(len, -1)
80    }
81
82    pub fn bump(&mut self, len: usize, delta: i8) -> bool {
83        if len == 0 {
84            return false;
85        }
86        let next = if delta >= 0 {
87            (self.selected + 1) % len
88        } else if self.selected == 0 {
89            len - 1
90        } else {
91            self.selected - 1
92        };
93        self.set_selected(next, len)
94    }
95}
96
97#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
98pub struct ScrollState {
99    pub offset_y: i32,
100    pub content_h: u32,
101}
102
103impl ScrollState {
104    pub const fn new(offset_y: i32, content_h: u32) -> Self {
105        Self {
106            offset_y,
107            content_h,
108        }
109    }
110
111    pub fn set_offset(&mut self, offset_y: i32) -> bool {
112        let next = offset_y.clamp(0, self.content_h as i32);
113        let changed = next != self.offset_y;
114        self.offset_y = next;
115        changed
116    }
117
118    pub fn scroll_by(&mut self, delta_y: i32) -> bool {
119        self.set_offset(self.offset_y.saturating_add(delta_y))
120    }
121}
122
123#[derive(Clone, Copy, Debug, PartialEq)]
124pub struct SliderState {
125    pub value: f32,
126    pub min: f32,
127    pub max: f32,
128}
129
130#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
131pub struct FeedTimelineState {
132    pub selected: usize,
133    pub offset: usize,
134    pub visible_rows: usize,
135    pub expanded: bool,
136}
137
138impl FeedTimelineState {
139    pub const fn new(selected: usize, offset: usize, visible_rows: usize, expanded: bool) -> Self {
140        Self {
141            selected,
142            offset,
143            visible_rows,
144            expanded,
145        }
146    }
147
148    pub fn set_selected(&mut self, selected: usize, len: usize) -> bool {
149        let next = selected.min(len.saturating_sub(1));
150        let changed = next != self.selected;
151        self.selected = next;
152        self.keep_selected_visible();
153        changed
154    }
155
156    pub fn bump(&mut self, len: usize, delta: i8) -> bool {
157        if len == 0 {
158            return false;
159        }
160        let next = if delta >= 0 {
161            (self.selected + 1) % len
162        } else if self.selected == 0 {
163            len - 1
164        } else {
165            self.selected - 1
166        };
167        self.set_selected(next, len)
168    }
169
170    pub fn set_expanded(&mut self, expanded: bool) -> bool {
171        let changed = self.expanded != expanded;
172        self.expanded = expanded;
173        changed
174    }
175
176    pub fn keep_selected_visible(&mut self) {
177        let rows = self.visible_rows.max(1);
178        if self.selected < self.offset {
179            self.offset = self.selected;
180        } else if self.selected >= self.offset.saturating_add(rows) {
181            self.offset = self.selected.saturating_add(1).saturating_sub(rows);
182        }
183    }
184}
185
186impl SliderState {
187    pub const fn new(value: f32, min: f32, max: f32) -> Self {
188        Self { value, min, max }
189    }
190
191    pub fn set_value(&mut self, value: f32) -> bool {
192        let next = value.clamp(self.min.min(self.max), self.min.max(self.max));
193        let changed = (next - self.value).abs() > f32::EPSILON;
194        self.value = next;
195        changed
196    }
197
198    pub fn step_by(&mut self, direction: f32) -> bool {
199        let step = ((self.max - self.min).abs() / 20.0).max(0.01);
200        self.set_value(self.value + step * direction)
201    }
202}