1use crate::context::Context;
2use crate::font::Fonts;
3use crate::framebuffer::{Framebuffer, UpdateMode};
4use crate::geom::Rectangle;
5use crate::gesture::GestureEvent;
6use crate::input::DeviceEvent;
7use crate::view::battery::Battery;
8use crate::view::clock::Clock;
9use crate::view::icon::Icon;
10use crate::view::label::Label;
11use crate::view::{Align, Bus, Event, Hub, Id, RenderData, RenderQueue, View, ViewId, ID_FEEDER};
12
13#[derive(Debug, Clone)]
15pub enum TopBarVariant {
16 Back,
18 Cancel(Event),
20 Search(Event),
22}
23
24pub struct TopBar {
25 id: Id,
26 rect: Rectangle,
27 children: Vec<Box<dyn View>>,
28}
29
30impl TopBar {
31 pub fn new(
32 rect: Rectangle,
33 variant: TopBarVariant,
34 title: String,
35 context: &mut Context,
36 ) -> TopBar {
37 let id = ID_FEEDER.next();
38 let mut children = Vec::new();
39
40 let side = rect.height() as i32;
41 let (icon_name, root_event) = match variant {
42 TopBarVariant::Back => ("back", Event::Back),
43 TopBarVariant::Cancel(event) => ("close", event),
44 TopBarVariant::Search(event) => ("search", event),
45 };
46
47 let root_icon = Icon::new(icon_name, rect![rect.min, rect.min + side], root_event);
48 children.push(Box::new(root_icon) as Box<dyn View>);
49
50 let mut clock_rect = rect![rect.max - pt!(4 * side, side), rect.max - pt!(3 * side, 0)];
51 let clock_label = Clock::new(&mut clock_rect, context);
52 let title_rect = rect![rect.min.x + side, rect.min.y, clock_rect.min.x, rect.max.y];
53 let title_label = Label::new(title_rect, title, Align::Center)
54 .event(Some(Event::ToggleNear(ViewId::TitleMenu, title_rect)));
55 children.push(Box::new(title_label) as Box<dyn View>);
56 children.push(Box::new(clock_label) as Box<dyn View>);
57
58 let capacity = context.battery.capacity().map_or(0.0, |v| v[0]);
59 let status = context
60 .battery
61 .status()
62 .map_or(crate::battery::Status::Discharging, |v| v[0]);
63 let battery_widget = Battery::new(
64 rect![rect.max - pt!(3 * side, side), rect.max - pt!(2 * side, 0)],
65 capacity,
66 status,
67 );
68 children.push(Box::new(battery_widget) as Box<dyn View>);
69
70 let name = if context.settings.frontlight {
71 "frontlight"
72 } else {
73 "frontlight-disabled"
74 };
75 let frontlight_icon = Icon::new(
76 name,
77 rect![rect.max - pt!(2 * side, side), rect.max - pt!(side, 0)],
78 Event::Show(ViewId::Frontlight),
79 );
80 children.push(Box::new(frontlight_icon) as Box<dyn View>);
81
82 let menu_rect = rect![rect.max - side, rect.max];
83 let menu_icon = Icon::new(
84 "menu",
85 menu_rect,
86 Event::ToggleNear(ViewId::MainMenu, menu_rect),
87 );
88 children.push(Box::new(menu_icon) as Box<dyn View>);
89
90 TopBar { id, rect, children }
91 }
92
93 pub fn update_root_icon(&mut self, name: &str, rq: &mut RenderQueue) {
94 let icon = self.child_mut(0).downcast_mut::<Icon>().unwrap();
95 if icon.name != name {
96 icon.name = name.to_string();
97 rq.add(RenderData::new(icon.id(), *icon.rect(), UpdateMode::Gui));
98 }
99 }
100
101 pub fn update_title_label(&mut self, title: &str, rq: &mut RenderQueue) {
102 let title_label = self.children[1].as_mut().downcast_mut::<Label>().unwrap();
103 title_label.update(title, rq);
104 }
105
106 pub fn update_frontlight_icon(&mut self, rq: &mut RenderQueue, context: &mut Context) {
107 let name = if context.settings.frontlight {
108 "frontlight"
109 } else {
110 "frontlight-disabled"
111 };
112 let icon = self.child_mut(4).downcast_mut::<Icon>().unwrap();
113 icon.name = name.to_string();
114 rq.add(RenderData::new(icon.id(), *icon.rect(), UpdateMode::Gui));
115 }
116
117 pub fn update_clock_label(&mut self, rq: &mut RenderQueue) {
118 if let Some(clock_label) = self.children[2].downcast_mut::<Clock>() {
119 clock_label.update(rq);
120 }
121 }
122
123 pub fn update_battery_widget(&mut self, rq: &mut RenderQueue, context: &mut Context) {
124 if let Some(battery_widget) = self.children[3].downcast_mut::<Battery>() {
125 battery_widget.update(rq, context);
126 }
127 }
128
129 pub fn reseed(&mut self, rq: &mut RenderQueue, context: &mut Context) {
130 self.update_frontlight_icon(rq, context);
131 self.update_clock_label(rq);
132 self.update_battery_widget(rq, context);
133 }
134}
135
136impl View for TopBar {
137 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, _bus, _rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
138 fn handle_event(
139 &mut self,
140 evt: &Event,
141 _hub: &Hub,
142 _bus: &mut Bus,
143 _rq: &mut RenderQueue,
144 _context: &mut Context,
145 ) -> bool {
146 match *evt {
147 Event::Gesture(GestureEvent::Tap(center))
148 | Event::Gesture(GestureEvent::HoldFingerShort(center, ..))
149 if self.rect.includes(center) =>
150 {
151 true
152 }
153 Event::Gesture(GestureEvent::Swipe { start, end, .. })
154 if self.rect.includes(start) && self.rect.includes(end) =>
155 {
156 true
157 }
158 Event::Device(DeviceEvent::Finger { position, .. }) if self.rect.includes(position) => {
159 true
160 }
161 _ => false,
162 }
163 }
164
165 #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _fb, _fonts, _rect), fields(rect = ?_rect)))]
166 fn render(&self, _fb: &mut dyn Framebuffer, _rect: Rectangle, _fonts: &mut Fonts) {}
167
168 fn resize(&mut self, rect: Rectangle, hub: &Hub, rq: &mut RenderQueue, context: &mut Context) {
169 let side = rect.height() as i32;
170 self.children[0].resize(rect![rect.min, rect.min + side], hub, rq, context);
171 let clock_width = self.children[2].rect().width() as i32;
172 let clock_rect = rect![
173 rect.max - pt!(3 * side + clock_width, side),
174 rect.max - pt!(3 * side, 0)
175 ];
176 self.children[1].resize(
177 rect![rect.min.x + side, rect.min.y, clock_rect.min.x, rect.max.y],
178 hub,
179 rq,
180 context,
181 );
182 self.children[2].resize(clock_rect, hub, rq, context);
183 self.children[3].resize(
184 rect![rect.max - pt!(3 * side, side), rect.max - pt!(2 * side, 0)],
185 hub,
186 rq,
187 context,
188 );
189 self.children[4].resize(
190 rect![rect.max - pt!(2 * side, side), rect.max - pt!(side, 0)],
191 hub,
192 rq,
193 context,
194 );
195 self.children[5].resize(rect![rect.max - side, rect.max], hub, rq, context);
196 self.rect = rect;
197 }
198
199 fn rect(&self) -> &Rectangle {
200 &self.rect
201 }
202
203 fn rect_mut(&mut self) -> &mut Rectangle {
204 &mut self.rect
205 }
206
207 fn children(&self) -> &Vec<Box<dyn View>> {
208 &self.children
209 }
210
211 fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
212 &mut self.children
213 }
214
215 fn id(&self) -> Id {
216 self.id
217 }
218}