//! Clock module: subscribes to second ticks, renders the time in the bar. //! Left-click toggles the seconds suffix; right-click opens a popup with //! the current time in large text. use iced::widget::{container, mouse_area, text}; use iced::{Element, Task}; use common::{BarModule, ClockKind, ClockPayload, ModuleEffect, ModuleMsg, Service}; /// Big-text popup size (logical px). const POPUP_W: u32 = 360; const POPUP_H: u32 = 160; /// A module-local message for the clock. #[derive(Clone)] pub enum ClockMsg { /// Toggle the seconds suffix. ToggleSeconds, /// Open the big-time popup. OpenPopup, } pub struct Clock { value: String, show_seconds: bool, } impl Clock { pub fn new() -> Self { Self { value: "--:--:--".to_string(), show_seconds: true, } } /// Display string: HH:MM:SS, or HH:MM when seconds are hidden. fn shown(&self) -> String { if self.show_seconds { self.value.clone() } else { self.value .split(':') // [hh, mm, ss] .take(2) .collect::>() .join(":") } } } impl Default for Clock { fn default() -> Self { Self::new() } } impl BarModule for Clock { fn id(&self) -> &'static str { "clock" } fn view(&self, window_id: Option) -> Element<'_, ModuleMsg> { match window_id { // Popup surface: current time in large text. Some(_) => container(text(&self.value).size(56)).padding(20).into(), // Bar surface: clickable time. Container carries the module id // so the popup can anchor to these bounds. None => container( mouse_area(text(self.shown()).size(16)) .on_press(ModuleMsg::new(self.id(), ClockMsg::ToggleSeconds)) .on_right_press(ModuleMsg::new(self.id(), ClockMsg::OpenPopup)), ) .id(iced::widget::Id::from(self.id())) .into(), } } fn update(&mut self, msg: ModuleMsg) -> Task { // Subscription fan-out delivers a raw `ClockPayload`, not `ClockMsg`. if let Some(payload) = msg.downcast::() { self.value = payload.value.clone(); return Task::none(); } match msg.downcast::() { Some(ClockMsg::ToggleSeconds) => { self.show_seconds = !self.show_seconds; Task::none() } Some(ClockMsg::OpenPopup) => Task::done(ModuleEffect::RequestPopup( self.id().to_string(), self.id().to_string(), )), None => Task::none(), } } fn services(&self) -> Vec { vec![Service::Clock(ClockKind::Seconds)] } fn popup_size(&self) -> Option<(u32, u32)> { Some((POPUP_W, POPUP_H)) } }