Mercurial > projects > dynamin
annotate dynamin/core/event.d @ 78:651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Sat, 06 Feb 2010 15:12:52 -0600 |
parents | c9a4850926d9 |
children | e7595d58f8a3 |
rev | line source |
---|---|
0 | 1 // Written in the D programming language |
2 // www.digitalmars.com/d/ | |
3 | |
4 /* | |
5 * The contents of this file are subject to the Mozilla Public License Version | |
6 * 1.1 (the "License"); you may not use this file except in compliance with | |
7 * the License. You may obtain a copy of the License at | |
8 * http://www.mozilla.org/MPL/ | |
9 * | |
10 * Software distributed under the License is distributed on an "AS IS" basis, | |
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 * for the specific language governing rights and limitations under the | |
13 * License. | |
14 * | |
15 * The Original Code is the Dynamin library. | |
16 * | |
17 * The Initial Developer of the Original Code is Jordan Miner. | |
18 * Portions created by the Initial Developer are Copyright (C) 2006-2009 | |
19 * the Initial Developer. All Rights Reserved. | |
20 * | |
21 * Contributor(s): | |
22 * Jordan Miner <jminer7@gmail.com> | |
23 * | |
24 */ | |
25 | |
26 module dynamin.core.event; | |
27 | |
28 import tango.io.Stdout; | |
29 import dynamin.core.global; | |
30 import tango.core.Exception; | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
31 public import tango.core.Traits; |
0 | 32 |
33 /** | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
34 * A struct used to notify handlers of an event. It is similar to .NET's events. |
0 | 35 * Here is an example of its usage: |
36 * ----- | |
37 * class Control { | |
38 * public { | |
39 * protected void whenPainting(PaintingEventArgs e) { | |
40 * /+ painting code goes here +/ | |
41 * } | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
42 * Event!(whenPainting) painting; |
0 | 43 * this() { |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
44 * painting.mainHandler = &whenPainting; |
0 | 45 * } |
46 * } | |
47 * } | |
48 * ----- | |
49 * Then to add a handler to it: | |
50 * ----- | |
51 * Control control = new Control(); | |
52 * control.painting += (PaintingEventArgs e) { | |
53 * /+ painting code goes here +/ | |
54 * }; | |
55 * ----- | |
56 * And fire it in the Control like this: | |
57 * ----- | |
58 * painting(new PaintingEventArgs()); | |
59 * ----- | |
60 * Not as easy to use as I would like, but still much better than Java's | |
61 * event handling. | |
62 * When the event is fired, all the handlers are called first, followed | |
63 * by the delegate passed into the constructor. | |
64 */ | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
65 struct Event(alias mainHandler_) { |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
66 alias ParameterTupleOf!(mainHandler_)[0] ArgsType; |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
67 /// void delegate(ArgsType e) |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
68 public alias void delegate(ArgsType e) Handler; |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
69 /// void delegate(ArgsType e) |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
70 public alias void delegate(ArgsType e) Dispatcher; |
0 | 71 |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
72 Handler[] handlers; |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
73 /// |
78
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
77
diff
changeset
|
74 private Handler mainHandler; |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
75 /// |
78
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
77
diff
changeset
|
76 private Dispatcher dispatcher; |
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
77
diff
changeset
|
77 void setUp(Handler mainHandler, Dispatcher dispatcher = null) { |
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
77
diff
changeset
|
78 this.mainHandler = mainHandler; |
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
77
diff
changeset
|
79 this.dispatcher = dispatcher; |
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
77
diff
changeset
|
80 } |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
81 void defaultDispatch(ArgsType e) { |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
82 callHandlers(e); |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
83 callMainHandler(e); |
0 | 84 } |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
85 |
0 | 86 /** |
87 * Calls all the handlers added to this event, passing e to them. | |
88 */ | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
89 void opCall(ArgsType e) { |
0 | 90 if(e is null) |
91 Stdout("Warning: EventArgs null").newline; | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
92 if(!dispatcher.funcptr) |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
93 defaultDispatch(e); |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
94 else |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
95 dispatcher(e); |
0 | 96 } |
97 /** | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
98 * Adds the specified handler to this event. The handler will be called |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
99 * when the event is fired. |
0 | 100 */ |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
101 void opAddAssign(Handler handler) { |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
102 if(!handler.funcptr) throw new Exception("handler cannot be null"); |
0 | 103 handlers.length = handlers.length + 1; |
104 handlers[length-1] = handler; | |
105 // TODO: use a list? | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
106 //handlers.add(handler); |
0 | 107 } |
108 /// ditto | |
109 void opAddAssign(void delegate() handler) { | |
110 struct Foo { | |
111 void delegate() handler; | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
112 void wrapper(ArgsType e) { handler(); } |
0 | 113 } |
114 Foo* f = new Foo; | |
115 f.handler = handler; | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
116 *this += &f.wrapper; |
0 | 117 // I really wish D could do this: |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
118 //this += (ArgsType e) { handler(); }; |
0 | 119 } |
120 /// TODO: implement this method | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
121 void opSubAssign(Handler handler) { |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
122 throw new Exception("removing handlers not yet implemented"); |
0 | 123 } |
124 /** | |
125 * Calls the handlers (not including the main handler) added to this event. | |
126 * Only use this method from a method that does custom dispatching. | |
127 */ | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
128 void callHandlers(ArgsType e) { |
0 | 129 foreach(handler; handlers) |
130 handler(e); | |
131 } | |
132 /** | |
133 * Calls the main handler unless the StopEventArgs.stopped has been | |
134 * set to true. | |
135 * Only use this method from a method that does custom dispatching. | |
136 */ | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
137 void callMainHandler(ArgsType e) { |
0 | 138 auto stopEventArgs = cast(StopEventArgs)e; |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
139 // if e is an instance of StopEventArgs, then check if it is stopped |
0 | 140 if(stopEventArgs is null || !stopEventArgs.stopped) |
141 mainHandler(e); | |
142 } | |
143 } | |
144 | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
145 // usage: mixin Event!(whenMoved) moved; |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
146 // mixin Event!(whenMoved, dispatchMoved) moved; |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
147 template Event2(alias mainHandler, alias dispatcher) { |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
148 private: |
0 | 149 alias ParameterTupleOf!(mainHandler)[0] ArgsType; |
150 /// void delegate(ArgsType e) | |
151 public alias void delegate(ArgsType e) Handler; | |
152 /// void delegate(ArgsType e) | |
153 public alias void delegate(ArgsType e) Dispatcher; | |
154 | |
155 // TODO: use a list-like struct? | |
156 Handler[] handlers; | |
157 public: | |
158 | |
159 /** | |
160 * Calls all the handlers added to this event, passing e to them. | |
161 */ | |
162 void opCall(ArgsType e) { | |
163 if(e is null) | |
164 Stdout("Warning: EventArgs null").newline; | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
165 dispatcher(e); |
0 | 166 } |
167 /** | |
168 * Adds the specified handler to this event. The handler will be called | |
169 * when the event is fired. | |
170 */ | |
171 void opAddAssign(Handler handler) { | |
172 if(!handler.funcptr) throw new Exception("handler cannot be null"); | |
173 handlers.length = handlers.length + 1; | |
174 handlers[length-1] = handler; | |
175 // TODO: use a list? | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
176 //handlers.add(handler); |
0 | 177 } |
178 /// ditto | |
179 void opAddAssign(void delegate() handler) { | |
180 struct Foo { | |
181 void delegate() handler; | |
182 void wrapper(ArgsType e) { handler(); } | |
183 } | |
184 Foo* f = new Foo; | |
185 f.handler = handler; | |
186 this += &f.wrapper; | |
187 // I really wish D could do this: | |
188 //this += (ArgsType e) { handler(); }; | |
189 } | |
190 /// TODO: implement this method | |
191 void opSubAssign(Handler handler) { | |
192 throw new Exception("removing handlers not yet implemented"); | |
193 } | |
194 /** | |
195 * Calls the handlers (not including the main handler) added to this event. | |
196 * Only use this method from a method that does custom dispatching. | |
197 */ | |
198 void callHandlers(ArgsType e) { | |
199 foreach(handler; handlers) | |
200 handler(e); | |
201 } | |
202 /** | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
203 * Calls the main handler unless the StopEventArgs.stopped has been |
0 | 204 * set to true. |
205 * Only use this method from a method that does custom dispatching. | |
206 */ | |
207 void callMainHandler(ArgsType e) { | |
208 auto stopEventArgs = cast(StopEventArgs)e; | |
209 // if e is an instance of StopEventArgs, then check if it is stopped | |
210 if(stopEventArgs is null || !stopEventArgs.stopped) | |
211 mainHandler(e); | |
212 } | |
213 } | |
214 | |
7
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
215 template Event2(alias mainHandler) { |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
216 alias ParameterTupleOf!(mainHandler)[0] ArgsType; |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
217 void defaultDispatch(ArgsType e) { |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
218 callHandlers(e); |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
219 callMainHandler(e); |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
220 } |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
221 mixin Event2!(mainHandler, defaultDispatch); |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
222 } |
1311fae1ca9b
Change template mixin (still unused) to take a dispatcher
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
223 |
0 | 224 /// The base class for passing arguments to event handlers. |
225 // TODO: shorter name? | |
226 class EventArgs { | |
227 } | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
228 /// |
0 | 229 class StopEventArgs : EventArgs { |
230 /** | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
231 * If stopped is set to true, then the Control will not respond to |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
232 * the event. For instance, if a key is typed while a text box is focused, |
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
7
diff
changeset
|
233 * but a handler sets stopped to true, the text box will not |
0 | 234 * respond to the key. |
235 */ | |
236 bool stopped = false; | |
237 } |