1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::time::Duration;

use chrono::prelude::*;
use failure::ResultExt;
use futures::{stream, Future, Stream};
use tokio_timer::Timer;

use super::{Widget, WidgetStream};
use crate::text::{Attributes, Text};
use crate::{Cnx, Result};

/// Shows the current time and date.
///
/// This widget shows the current time and date, in the form `%Y-%m-%d %a %I:%M
/// %p`, e.g. `2017-09-01 Fri 12:51 PM`.
pub struct Clock {
    timer: Timer,
    attr: Attributes,
}

impl Clock {
    /// Creates a new Clock widget.
    ///
    /// Creates a new `Clock` widget, whose text will be displayed with the
    /// given [`Attributes`].
    ///
    /// The [`Cnx`] instance is borrowed during construction in order to get
    /// access to handles of its event loop. However, it is not borrowed for the
    /// lifetime of the widget. See the [`cnx_add_widget!()`] for more
    /// discussion about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// #
    /// # fn run() -> ::cnx::Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top)?;
    /// cnx_add_widget!(cnx, Clock::new(&cnx, attr.clone()));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(cnx: &Cnx, attr: Attributes) -> Clock {
        Clock {
            timer: cnx.timer(),
            attr,
        }
    }
}

impl Widget for Clock {
    fn stream(self: Box<Self>) -> Result<WidgetStream> {
        // As we're not showing seconds, we can sleep for however long it takes
        // until the minutes changes between updates. Initially sleep for 0 seconds
        // so that our `self.timer.sleep()` expires immediately.
        let sleep_for = Duration::from_secs(0);
        let stream = stream::unfold(sleep_for, move |sleep_for| {
            // Avoid having to move self into the .map() closure.
            let attr = self.attr.clone();
            Some(self.timer.sleep(sleep_for).map(move |()| {
                let now = Local::now();
                let formatted = now.format("%Y-%m-%d %a %I:%M %p").to_string();
                let texts = vec![Text {
                    attr: attr,
                    text: formatted,
                    stretch: false,
                }];

                let sleep_for = Duration::from_secs(60 - u64::from(now.second()));
                (texts, sleep_for)
            }))
        })
        .then(|r| r.context("Error in tokio_timer stream"))
        .map_err(|e| e.into());

        Ok(Box::new(stream))
    }
}