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