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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::controls::ControlHandle;
use crate::win32::{window_helper as wh, window::build_timer};
use crate::NwgError;
use std::cell::RefCell;

const NOT_BOUND: &'static str = "Timer is not yet bound to a winapi object";
const UNUSABLE_TIMER: &'static str = "Timer parent window was freed";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: Timer handle is not Timer!";


/**
A timer is an invisible UI component that trigger the `OnTimerTick` event at the specified interval.
Timers are mosty used to handle animations OR to create a timeout. To sync multithreaded action see the `Notice` object.

A timer still requires a top level window parent. If the top level window parent is destroyed, the timer becomes invalid.

Note that timer SHOULD NOT be used when a consistent interval is needed. The timer event might be triggered much faster
than the `interval` value. For example, when a user resize a window, Timer OnTimerTick gets triggered each time the window size changes.

Requires the `timer` feature. 

**Builder parameters:**
  * `parent`:   **Required.** The button parent container. Should be a top level window
  * `interval`:  The timer tick interval in millisecond
  * `stopped`:   If the timer should start right away. By default timers starts "stopped(true)". Be sure to include `stopped(false)` in your builder if you want the timer to start instantly.

**Control events:**
  * `OnTimerTick`: When the timer ticks

```
use native_windows_gui as nwg;

fn build_timer(parent: &nwg::Window)  {
    let mut timer = Default::default();
    nwg::Timer::builder()
        .parent(parent)
        .interval(100)
        .stopped(false)
        .build(&mut timer);
}
```
*/
#[derive(Default)]
pub struct Timer {
    pub handle: ControlHandle,
    interval: RefCell<u32>,
}

impl Timer {

    pub fn builder() -> TimerBuilder {
        TimerBuilder {
            parent: None,
            interval: 100,
            stopped: true
        }
    }

    /// Checks if the timer is still usable. A timer becomes unusable when the parent window is destroyed.

    /// This will also return false if the timer is not initialized.

    pub fn valid(&self) -> bool {
        if self.handle.blank() { return false; }
        let (hwnd, _) = self.handle.timer().expect(BAD_HANDLE);
        wh::window_valid(hwnd)
    }

    /// Returns the interval of the timer, in milliseconds.

    pub fn interval(&self) -> u32 {
        *self.interval.borrow()
    }

    /// Sets the interval of the timer, in milliseconds.

    pub fn set_interval(&self, i: u32) {
        *self.interval.borrow_mut() = i;
    }

    /// Stops the timer.

    pub fn stop(&self) {
        if self.handle.blank() { panic!(NOT_BOUND); }
        if !self.valid() { panic!(UNUSABLE_TIMER); }
        let (hwnd, id) = self.handle.timer().expect(BAD_HANDLE);

        wh::kill_timer(hwnd, id);
    }

    /// Starts the timer. If the timer is already running, this restarts it.

    pub fn start(&self) {
        if self.handle.blank() { panic!(NOT_BOUND); }
        if !self.valid() { panic!(UNUSABLE_TIMER); }
        let (hwnd, id) = self.handle.timer().expect(BAD_HANDLE);

        wh::start_timer(hwnd, id, self.interval());
    }

}

impl Drop for Timer {
    fn drop(&mut self) {
        self.handle.destroy();
    }
}

pub struct TimerBuilder {
    parent: Option<ControlHandle>,
    interval: u32,
    stopped: bool
}

impl TimerBuilder {
    
    pub fn interval(mut self, interval: u32) -> TimerBuilder {
        self.interval = interval;
        self
    }

    pub fn stopped(mut self, stop: bool) -> TimerBuilder {
        self.stopped = stop;
        self
    }

    pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> TimerBuilder {
        self.parent = Some(p.into());
        self
    }

    pub fn build(self, out: &mut Timer) -> Result<(), NwgError> {
        let parent = match self.parent {
            Some(p) => match p.hwnd() {
                Some(handle) => Ok(handle),
                None => Err(NwgError::control_create("Wrong parent type"))
            },
            None => Err(NwgError::no_parent("Timer"))
        }?;

        out.handle = unsafe { build_timer(parent, self.interval, self.stopped) };
        out.set_interval(self.interval);
        
        Ok(())
    }

}

impl PartialEq for Timer {
    fn eq(&self, other: &Self) -> bool {
        self.handle == other.handle
    }
}