Skip to main content

native_windows_gui2/controls/
timer.rs

1#![allow(deprecated)]
2
3use crate::NwgError;
4use crate::controls::ControlHandle;
5use crate::win32::{window::build_timer, window_helper as wh};
6use std::cell::RefCell;
7
8const NOT_BOUND: &'static str = "Timer is not yet bound to a winapi object";
9const UNUSABLE_TIMER: &'static str = "Timer parent window was freed";
10const BAD_HANDLE: &'static str = "INTERNAL ERROR: Timer handle is not Timer!";
11
12/**
13WARNING: Use AnimationTimer instead. The winapi timer does not have a constant tick and will call your single threaded from another thread.
14
15A timer is an invisible UI component that trigger the `OnTimerTick` event at the specified interval.
16Timers are mosty used to handle animations OR to create a timeout. To sync multithreaded action see the `Notice` object.
17
18A timer still requires a top level window parent. If the top level window parent is destroyed, the timer becomes invalid.
19
20Note that timer SHOULD NOT be used when a consistent interval is needed. The timer event might be triggered much faster
21than the `interval` value. For example, when a user resize a window, Timer OnTimerTick gets triggered each time the window size changes.
22This is a Windows "feature", there's probably nothing I can do to fix that.
23
24
25Requires the `timer` feature.
26
27**Builder parameters:**
28  * `parent`:   **Required.** The timer parent container. Should be a top level window
29  * `interval`:  The timer tick interval in millisecond
30  * `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.
31
32**Control events:**
33  * `OnTimerTick`: When the timer ticks
34
35```
36use native_windows_gui2 as nwg;
37
38fn build_timer(parent: &nwg::Window)  {
39    let mut timer = Default::default();
40    nwg::Timer::builder()
41        .parent(parent)
42        .interval(100)
43        .stopped(false)
44        .build(&mut timer);
45}
46```
47*/
48#[deprecated(
49    since = "1.0.11",
50    note = "Use AnimationTimer instead. The winapi timer does not have a constant tick and will call your single threaded from another thread."
51)]
52#[derive(Default)]
53pub struct Timer {
54    pub handle: ControlHandle,
55    interval: RefCell<u32>,
56}
57
58impl Timer {
59    pub fn builder() -> TimerBuilder {
60        TimerBuilder {
61            parent: None,
62            interval: 100,
63            stopped: true,
64        }
65    }
66
67    /// Checks if the timer is still usable. A timer becomes unusable when the parent window is destroyed.
68    /// This will also return false if the timer is not initialized.
69    pub fn valid(&self) -> bool {
70        if self.handle.blank() {
71            return false;
72        }
73        let (hwnd, _) = self.handle.timer().expect(BAD_HANDLE);
74        wh::window_valid(hwnd)
75    }
76
77    /// Returns the interval of the timer, in milliseconds.
78    pub fn interval(&self) -> u32 {
79        *self.interval.borrow()
80    }
81
82    /// Sets the interval of the timer, in milliseconds.
83    pub fn set_interval(&self, i: u32) {
84        *self.interval.borrow_mut() = i;
85    }
86
87    /// Stops the timer.
88    pub fn stop(&self) {
89        if self.handle.blank() {
90            panic!("{}", NOT_BOUND);
91        }
92        if !self.valid() {
93            panic!("{}", UNUSABLE_TIMER);
94        }
95        let (hwnd, id) = self.handle.timer().expect(BAD_HANDLE);
96
97        wh::kill_timer(hwnd, id);
98    }
99
100    /// Starts the timer. If the timer is already running, this restarts it.
101    pub fn start(&self) {
102        if self.handle.blank() {
103            panic!("{}", NOT_BOUND);
104        }
105        if !self.valid() {
106            panic!("{}", UNUSABLE_TIMER);
107        }
108        let (hwnd, id) = self.handle.timer().expect(BAD_HANDLE);
109
110        wh::start_timer(hwnd, id, self.interval());
111    }
112}
113
114impl Drop for Timer {
115    fn drop(&mut self) {
116        self.handle.destroy();
117    }
118}
119
120pub struct TimerBuilder {
121    parent: Option<ControlHandle>,
122    interval: u32,
123    stopped: bool,
124}
125
126impl TimerBuilder {
127    pub fn interval(mut self, interval: u32) -> TimerBuilder {
128        self.interval = interval;
129        self
130    }
131
132    pub fn stopped(mut self, stop: bool) -> TimerBuilder {
133        self.stopped = stop;
134        self
135    }
136
137    pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> TimerBuilder {
138        self.parent = Some(p.into());
139        self
140    }
141
142    pub fn build(self, out: &mut Timer) -> Result<(), NwgError> {
143        let parent = match self.parent {
144            Some(p) => match p.hwnd() {
145                Some(handle) => Ok(handle),
146                None => Err(NwgError::control_create("Wrong parent type")),
147            },
148            None => Err(NwgError::no_parent("Timer")),
149        }?;
150
151        *out = Default::default();
152
153        out.handle = unsafe { build_timer(parent, self.interval, self.stopped) };
154        out.set_interval(self.interval);
155
156        Ok(())
157    }
158}
159
160impl PartialEq for Timer {
161    fn eq(&self, other: &Self) -> bool {
162        self.handle == other.handle
163    }
164}