cadmus_core/view/
clock.rs

1use super::{Bus, Event, Hub, Id, RenderData, RenderQueue, View, ViewId, ID_FEEDER};
2use crate::color::{BLACK, WHITE};
3use crate::context::Context;
4use crate::device::CURRENT_DEVICE;
5use crate::font::{font_from_style, Fonts, NORMAL_STYLE};
6use crate::framebuffer::{Framebuffer, UpdateMode};
7use crate::geom::Rectangle;
8use crate::gesture::GestureEvent;
9use chrono::{DateTime, Local};
10
11pub struct Clock {
12    id: Id,
13    rect: Rectangle,
14    children: Vec<Box<dyn View>>,
15    format: String,
16    time: DateTime<Local>,
17}
18
19impl Clock {
20    pub fn new(rect: &mut Rectangle, context: &mut Context) -> Clock {
21        let time = Local::now();
22        let format = context.settings.time_format.clone();
23        let font = font_from_style(&mut context.fonts, &NORMAL_STYLE, CURRENT_DEVICE.dpi);
24        let width = font
25            .plan(&time.format(&format).to_string(), None, None)
26            .width
27            + font.em() as i32;
28        rect.min.x = rect.max.x - width;
29        Clock {
30            id: ID_FEEDER.next(),
31            rect: *rect,
32            children: Vec::new(),
33            format,
34            time,
35        }
36    }
37
38    pub fn update(&mut self, rq: &mut RenderQueue) {
39        self.time = Local::now();
40        rq.add(RenderData::new(self.id, self.rect, UpdateMode::Gui));
41    }
42}
43
44impl View for Clock {
45    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, _hub, bus, rq, _context), fields(event = ?evt), ret(level=tracing::Level::TRACE)))]
46    fn handle_event(
47        &mut self,
48        evt: &Event,
49        _hub: &Hub,
50        bus: &mut Bus,
51        rq: &mut RenderQueue,
52        _context: &mut Context,
53    ) -> bool {
54        match *evt {
55            Event::ClockTick => {
56                self.update(rq);
57                true
58            }
59            Event::Gesture(GestureEvent::Tap(center)) if self.rect.includes(center) => {
60                bus.push_back(Event::ToggleNear(ViewId::ClockMenu, self.rect));
61                true
62            }
63            _ => false,
64        }
65    }
66
67    #[cfg_attr(feature = "otel", tracing::instrument(skip(self, fb, fonts, _rect), fields(rect = ?_rect)))]
68    fn render(&self, fb: &mut dyn Framebuffer, _rect: Rectangle, fonts: &mut Fonts) {
69        let dpi = CURRENT_DEVICE.dpi;
70        let font = font_from_style(fonts, &NORMAL_STYLE, dpi);
71        let plan = font.plan(&self.time.format(&self.format).to_string(), None, None);
72        let dx = (self.rect.width() as i32 - plan.width) / 2;
73        let dy = (self.rect.height() as i32 - font.x_heights.0 as i32) / 2;
74        let pt = pt!(self.rect.min.x + dx, self.rect.max.y - dy);
75
76        fb.draw_rectangle(&self.rect, WHITE);
77        font.render(fb, BLACK, &plan, pt);
78    }
79
80    fn rect(&self) -> &Rectangle {
81        &self.rect
82    }
83
84    fn rect_mut(&mut self) -> &mut Rectangle {
85        &mut self.rect
86    }
87
88    fn children(&self) -> &Vec<Box<dyn View>> {
89        &self.children
90    }
91
92    fn children_mut(&mut self) -> &mut Vec<Box<dyn View>> {
93        &mut self.children
94    }
95
96    fn id(&self) -> Id {
97        self.id
98    }
99}