cadmus_core/view/settings_editor/
bottom_bar.rs1use crate::color::WHITE;
2use crate::font::Fonts;
3use crate::framebuffer::Framebuffer;
4use crate::geom::Rectangle;
5use crate::view::filler::Filler;
6use crate::view::icon::Icon;
7use crate::view::{Event, Id, View, ID_FEEDER};
8
9#[derive(Debug, Clone)]
11pub enum BottomBarVariant {
12 SingleButton {
14 event: Event,
16 icon: &'static str,
18 },
19 TwoButtons {
21 left_event: Event,
23 left_icon: &'static str,
25 right_event: Event,
27 right_icon: &'static str,
29 },
30}
31
32pub struct SettingsEditorBottomBar {
37 id: Id,
38 rect: Rectangle,
39 children: Vec<Box<dyn View>>,
40}
41
42impl SettingsEditorBottomBar {
43 pub fn new(rect: Rectangle, variant: BottomBarVariant) -> Self {
71 let id = ID_FEEDER.next();
72 let mut children = Vec::new();
73
74 let background = Filler::new(rect, WHITE);
75 children.push(Box::new(background) as Box<dyn View>);
76
77 match variant {
78 BottomBarVariant::SingleButton {
79 event,
80 icon: icon_name,
81 } => {
82 let icon = Icon::new(icon_name, rect, event);
83 children.push(Box::new(icon) as Box<dyn View>);
84 }
85 BottomBarVariant::TwoButtons {
86 left_event,
87 left_icon,
88 right_event,
89 right_icon,
90 } => {
91 let button_width = rect.width() as i32 / 2;
92
93 let left_rect = rect![
94 rect.min.x,
95 rect.min.y,
96 rect.min.x + button_width,
97 rect.max.y
98 ];
99 let left_button = Icon::new(left_icon, left_rect, left_event);
100 children.push(Box::new(left_button) as Box<dyn View>);
101
102 let right_rect = rect![
103 rect.min.x + button_width,
104 rect.min.y,
105 rect.max.x,
106 rect.max.y
107 ];
108 let right_button = Icon::new(right_icon, right_rect, right_event);
109 children.push(Box::new(right_button) as Box<dyn View>);
110 }
111 }
112
113 SettingsEditorBottomBar { id, rect, children }
114 }
115}
116
117impl View for SettingsEditorBottomBar {
118 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, _bus, _rq, _context), fields(event = ?_evt), ret(level=tracing::Level::TRACE)))]
119 fn handle_event(
120 &mut self,
121 _evt: &Event,
122 _hub: &crate::view::Hub,
123 _bus: &mut crate::view::Bus,
124 _rq: &mut crate::view::RenderQueue,
125 _context: &mut crate::context::Context,
126 ) -> bool {
127 false
128 }
129
130 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _fb, _fonts), fields(rect = ?_rect)))]
131 fn render(&self, _fb: &mut dyn Framebuffer, _rect: Rectangle, _fonts: &mut Fonts) {}
132
133 fn rect(&self) -> &Rectangle {
134 &self.rect
135 }
136
137 fn rect_mut(&mut self) -> &mut Rectangle {
138 &mut self.rect
139 }
140
141 fn children(&self) -> &Vec<Box<dyn View>> {
142 &self.children
143 }
144
145 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
146 &mut self.children
147 }
148
149 fn id(&self) -> Id {
150 self.id
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use crate::geom::Point;
158
159 #[test]
160 fn test_single_button_creates_two_children() {
161 let rect = Rectangle::new(Point { x: 0, y: 0 }, Point { x: 100, y: 50 });
162
163 let bottom_bar = SettingsEditorBottomBar::new(
164 rect,
165 BottomBarVariant::SingleButton {
166 event: Event::Back,
167 icon: "back",
168 },
169 );
170
171 assert_eq!(
172 bottom_bar.children().len(),
173 2,
174 "SingleButton variant should have 2 children: background filler and icon"
175 );
176 }
177
178 #[test]
179 fn test_two_buttons_creates_three_children() {
180 let rect = Rectangle::new(Point { x: 0, y: 0 }, Point { x: 100, y: 50 });
181
182 let bottom_bar = SettingsEditorBottomBar::new(
183 rect,
184 BottomBarVariant::TwoButtons {
185 left_event: Event::Back,
186 left_icon: "back",
187 right_event: Event::Validate,
188 right_icon: "check_mark",
189 },
190 );
191
192 assert_eq!(
193 bottom_bar.children().len(),
194 3,
195 "TwoButtons variant should have 3 children: background filler, left icon, and right icon"
196 );
197 }
198
199 #[test]
200 fn test_two_buttons_split_width_evenly() {
201 let rect = Rectangle::new(Point { x: 0, y: 0 }, Point { x: 200, y: 50 });
202
203 let bottom_bar = SettingsEditorBottomBar::new(
204 rect,
205 BottomBarVariant::TwoButtons {
206 left_event: Event::Back,
207 left_icon: "back",
208 right_event: Event::Validate,
209 right_icon: "check_mark",
210 },
211 );
212
213 let children = bottom_bar.children();
214 let left_button_rect = children[1].rect();
215 let right_button_rect = children[2].rect();
216
217 assert_eq!(
218 left_button_rect.width(),
219 100,
220 "Left button should be 100 units wide"
221 );
222 assert_eq!(
223 right_button_rect.width(),
224 100,
225 "Right button should be 100 units wide"
226 );
227 assert_eq!(left_button_rect.min.x, 0);
228 assert_eq!(left_button_rect.max.x, 100);
229 assert_eq!(right_button_rect.min.x, 100);
230 assert_eq!(right_button_rect.max.x, 200);
231 }
232}