1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 
5 ///
6 module dfl.timer;
7 
8 private import dfl.internal.winapi, dfl.event, dfl.base, dfl.application,
9 	dfl.internal.dlib;
10 
11 
12 ///
13 class Timer // docmain
14 {
15 	//EventHandler tick;
16 	Event!(Timer, EventArgs) tick; ///
17 	
18 	
19 	///
20 	@property void enabled(bool on) // setter
21 	{
22 		if(on)
23 			start();
24 		else
25 			stop();
26 	}
27 	
28 	/// ditto
29 	@property bool enabled() // getter
30 	{
31 		return timerId != 0;
32 	}
33 	
34 	
35 	///
36 	final @property void interval(size_t timeout) // setter
37 	{
38 		if(!timeout)
39 			throw new DflException("Invalid timer interval");
40 		
41 		if(this._timeout != timeout)
42 		{
43 			this._timeout = timeout;
44 			
45 			if(timerId)
46 			{
47 				// I don't know if this is the correct behavior.
48 				// Reset the timer for the new timeout...
49 				stop();
50 				start();
51 			}
52 		}
53 	}
54 	
55 	/// ditto
56 	final @property size_t interval() // getter
57 	{
58 		return _timeout;
59 	}
60 	
61 	
62 	///
63 	final void start()
64 	{
65 		if(timerId)
66 			return;
67 		
68 		assert(_timeout > 0);
69 		
70 		timerId = SetTimer(null, 0, _timeout, &timerProc);
71 		if(!timerId)
72 			throw new DflException("Unable to start timer");
73 		allTimers[timerId] = this;
74 	}
75 	
76 	/// ditto
77 	final void stop()
78 	{
79 		if(timerId)
80 		{
81 			//delete allTimers[timerId];
82 			allTimers.remove(timerId);
83 			KillTimer(null, timerId);
84 			timerId = 0;
85 		}
86 	}
87 	
88 	
89 	///
90 	this()
91 	{
92 	}
93 	
94 	/// ditto
95 	this(void delegate(Timer) dg)
96 	{
97 		this();
98 		if(dg)
99 		{
100 			this._dg = dg;
101 			tick ~= &_dgcall;
102 		}
103 	}
104 	
105 	/// ditto
106 	this(void delegate(Object, EventArgs) dg)
107 	{
108 		assert(dg !is null);
109 		
110 		this();
111 		tick ~= dg;
112 	}
113 	
114 	/// ditto
115 	this(void delegate(Timer, EventArgs) dg)
116 	{
117 		assert(dg !is null);
118 		
119 		this();
120 		tick ~= dg;
121 	}
122 	
123 	
124 	~this()
125 	{
126 		dispose();
127 	}
128 	
129 	
130 	protected:
131 	
132 	void dispose()
133 	{
134 		stop();
135 	}
136 	
137 	
138 	///
139 	void onTick(EventArgs ea)
140 	{
141 		tick(this, ea);
142 	}
143 	
144 	
145 	private:
146 	DWORD _timeout = 100;
147 	UINT timerId = 0;
148 	void delegate(Timer) _dg;
149 	
150 	
151 	void _dgcall(Object sender, EventArgs ea)
152 	{
153 		assert(_dg !is null);
154 		_dg(this);
155 	}
156 }
157 
158 
159 private:
160 
161 Timer[UINT] allTimers;
162 
163 
164 extern(Windows) void timerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) nothrow
165 {
166 	try
167 	{
168 		if(idEvent in allTimers)
169 		{
170 			allTimers[idEvent].onTick(EventArgs.empty);
171 		}
172 		else
173 		{
174 			debug(APP_PRINT)
175 				cprintf("Unknown timer 0x%X.\n", idEvent);
176 		}
177 	}
178 	catch(DThrowable e)
179 	{
180 		Application.onThreadException(e);
181 	}
182 }
183