diff options
Diffstat (limited to 'examples/clock/src')
-rw-r--r-- | examples/clock/src/main.rs | 176 |
1 files changed, 58 insertions, 118 deletions
diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs index d8266f06..b317ac00 100644 --- a/examples/clock/src/main.rs +++ b/examples/clock/src/main.rs @@ -1,9 +1,10 @@ use iced::{ - canvas, executor, Application, Canvas, Color, Command, Container, Element, - Length, Point, Settings, Subscription, Vector, + canvas::{self, Cache, Canvas, Cursor, Geometry, LineCap, Path, Stroke}, + executor, time, Application, Color, Command, Container, Element, Length, + Point, Rectangle, Settings, Subscription, Vector, }; -pub fn main() { +pub fn main() -> iced::Result { Clock::run(Settings { antialiasing: true, ..Settings::default() @@ -11,8 +12,8 @@ pub fn main() { } struct Clock { - now: LocalTime, - clock: canvas::layer::Cache<LocalTime>, + now: chrono::DateTime<chrono::Local>, + clock: Cache, } #[derive(Debug, Clone, Copy)] @@ -23,12 +24,13 @@ enum Message { impl Application for Clock { type Executor = executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Self, Command<Message>) { + fn new(_flags: ()) -> (Self, Command<Message>) { ( Clock { - now: chrono::Local::now().into(), - clock: canvas::layer::Cache::new(), + now: chrono::Local::now(), + clock: Default::default(), }, Command::none(), ) @@ -41,7 +43,7 @@ impl Application for Clock { fn update(&mut self, message: Message) -> Command<Message> { match message { Message::Tick(local_time) => { - let now = local_time.into(); + let now = local_time; if now != self.now { self.now = now; @@ -54,140 +56,78 @@ impl Application for Clock { } fn subscription(&self) -> Subscription<Message> { - time::every(std::time::Duration::from_millis(500)).map(Message::Tick) + time::every(std::time::Duration::from_millis(500)) + .map(|_| Message::Tick(chrono::Local::now())) } fn view(&mut self) -> Element<Message> { - let canvas = Canvas::new() + let canvas = Canvas::new(self) .width(Length::Units(400)) - .height(Length::Units(400)) - .push(self.clock.with(&self.now)); + .height(Length::Units(400)); Container::new(canvas) .width(Length::Fill) .height(Length::Fill) + .padding(20) .center_x() .center_y() .into() } } -#[derive(Debug, PartialEq, Eq)] -struct LocalTime { - hour: u32, - minute: u32, - second: u32, -} - -impl From<chrono::DateTime<chrono::Local>> for LocalTime { - fn from(date_time: chrono::DateTime<chrono::Local>) -> LocalTime { +impl canvas::Program<Message> for Clock { + fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec<Geometry> { use chrono::Timelike; - LocalTime { - hour: date_time.hour(), - minute: date_time.minute(), - second: date_time.second(), - } - } -} + let clock = self.clock.draw(bounds.size(), |frame| { + let center = frame.center(); + let radius = frame.width().min(frame.height()) / 2.0; -impl canvas::Drawable for LocalTime { - fn draw(&self, frame: &mut canvas::Frame) { - let center = frame.center(); - let radius = frame.width().min(frame.height()) / 2.0; - let offset = Vector::new(center.x, center.y); - - let clock = canvas::Path::new(|path| path.circle(center, radius)); - - frame.fill( - &clock, - canvas::Fill::Color(Color::from_rgb8(0x12, 0x93, 0xD8)), - ); - - fn draw_hand( - n: u32, - total: u32, - length: f32, - offset: Vector, - path: &mut canvas::path::Builder, - ) { - let turns = n as f32 / total as f32; - let t = 2.0 * std::f32::consts::PI * (turns - 0.25); - - let x = length * t.cos(); - let y = length * t.sin(); - - path.line_to(Point::new(x, y) + offset); - } + let background = Path::circle(center, radius); + frame.fill(&background, Color::from_rgb8(0x12, 0x93, 0xD8)); - let hour_and_minute_hands = canvas::Path::new(|path| { - path.move_to(center); - draw_hand(self.hour, 12, 0.5 * radius, offset, path); + let short_hand = + Path::line(Point::ORIGIN, Point::new(0.0, -0.5 * radius)); - path.move_to(center); - draw_hand(self.minute, 60, 0.8 * radius, offset, path) - }); + let long_hand = + Path::line(Point::ORIGIN, Point::new(0.0, -0.8 * radius)); - frame.stroke( - &hour_and_minute_hands, - canvas::Stroke { - width: 6.0, + let thin_stroke = Stroke { + width: radius / 100.0, color: Color::WHITE, - line_cap: canvas::LineCap::Round, - ..canvas::Stroke::default() - }, - ); - - let second_hand = canvas::Path::new(|path| { - path.move_to(center); - draw_hand(self.second, 60, 0.8 * radius, offset, path) + line_cap: LineCap::Round, + ..Stroke::default() + }; + + let wide_stroke = Stroke { + width: thin_stroke.width * 3.0, + ..thin_stroke + }; + + frame.translate(Vector::new(center.x, center.y)); + + frame.with_save(|frame| { + frame.rotate(hand_rotation(self.now.hour(), 12)); + frame.stroke(&short_hand, wide_stroke); + }); + + frame.with_save(|frame| { + frame.rotate(hand_rotation(self.now.minute(), 60)); + frame.stroke(&long_hand, wide_stroke); + }); + + frame.with_save(|frame| { + frame.rotate(hand_rotation(self.now.second(), 60)); + frame.stroke(&long_hand, thin_stroke); + }) }); - frame.stroke( - &second_hand, - canvas::Stroke { - width: 3.0, - color: Color::WHITE, - line_cap: canvas::LineCap::Round, - ..canvas::Stroke::default() - }, - ); + vec![clock] } } -mod time { - use iced::futures; +fn hand_rotation(n: u32, total: u32) -> f32 { + let turns = n as f32 / total as f32; - pub fn every( - duration: std::time::Duration, - ) -> iced::Subscription<chrono::DateTime<chrono::Local>> { - iced::Subscription::from_recipe(Every(duration)) - } - - struct Every(std::time::Duration); - - impl<H, I> iced_native::subscription::Recipe<H, I> for Every - where - H: std::hash::Hasher, - { - type Output = chrono::DateTime<chrono::Local>; - - fn hash(&self, state: &mut H) { - use std::hash::Hash; - - std::any::TypeId::of::<Self>().hash(state); - self.0.hash(state); - } - - fn stream( - self: Box<Self>, - _input: futures::stream::BoxStream<'static, I>, - ) -> futures::stream::BoxStream<'static, Self::Output> { - use futures::stream::StreamExt; - - async_std::stream::interval(self.0) - .map(|_| chrono::Local::now()) - .boxed() - } - } + 2.0 * std::f32::consts::PI * turns } |