root/trunk/gtk/old/event.d

Revision 8, 5.8 kB (checked in by Chris Miller, 5 years ago)

First steps of DFL GTK.

Line 
1 // Not actually part of forms, but is needed.
2 // This code is public domain.
3
4 /// Event handling.
5 module dfl.event;
6
7 import dfl.internal.dlib;
8
9
10 // Create an event handler; old style.
11 template Event(TArgs : EventArgs = EventArgs) // docmain
12 {
13     alias Event!(Object, TArgs) Event;
14 }
15
16
17 /** Managing event handlers.
18     Params:
19         T1 = the sender type.
20         T2 = the event arguments type.
21 **/
22 template Event(T1, T2) // docmain
23 {
24     /// Managing event handlers.
25     struct Event // docmain
26     {
27         alias void delegate(T1, T2) Handler; /// Event handler type.
28        
29        
30         /// Add an event handler with the exact type.
31         void addHandlerExact(Handler handler)
32         in
33         {
34             assert(handler);
35         }
36         body
37         {
38             if(!_array.length)
39             {
40                 _array = new Handler[2];
41                 _array[1] = handler;
42                 unsetHot();
43             }
44             else
45             {
46                 if(!isHot())
47                 {
48                     _array ~= handler;
49                 }
50                 else // Hot.
51                 {
52                     _array = _array ~ (&handler)[0 .. 1]; // Force duplicate.
53                     unsetHot();
54                 }
55             }
56         }
57        
58        
59         /// Add an event handler with parameter contravariance.
60         void addHandler(TDG)(TDG handler)
61         in
62         {
63             assert(handler);
64         }
65         body
66         {
67             mixin _validateHandler!(TDG);
68            
69             addHandlerExact(cast(Handler)handler);
70         }
71        
72        
73         /// Shortcut for addHandler().
74         void opCatAssign(TDG)(TDG handler)
75         {
76             addHandler!(TDG)(handler);
77         }
78        
79        
80         /// Remove the specified event handler with the exact Handler type.
81         void removeHandlerExact(Handler handler)
82         {
83             if(!_array.length)
84                 return;
85            
86             size_t iw;
87             for(iw = 1; iw != _array.length; iw++)
88             {
89                 if(handler == _array[iw])
90                 {
91                     if(iw == 1 && _array.length == 2)
92                     {
93                         _array = null;
94                         break;
95                     }
96                    
97                     if(iw == _array.length - 1)
98                     {
99                         _array[iw] = null;
100                         _array = _array[0 .. iw];
101                         break;
102                     }
103                    
104                     if(!isHot())
105                     {
106                         _array[iw] = _array[_array.length - 1];
107                         _array[_array.length - 1] = null;
108                         _array = _array[0 .. _array.length - 1];
109                     }
110                     else // Hot.
111                     {
112                         _array = _array[0 .. iw] ~ _array[iw + 1 .. _array.length]; // Force duplicate.
113                         unsetHot();
114                     }
115                     break;
116                 }
117             }
118         }
119        
120        
121         /// Remove the specified event handler with parameter contravariance.
122         void removeHandler(TDG)(TDG handler)
123         {
124             mixin _validateHandler!(TDG);
125            
126             removeHandlerExact(cast(Handler)handler);
127         }
128        
129        
130         /// Fire the event handlers.
131         void opCall(T1 v1, T2 v2)
132         {
133             if(!_array.length)
134                 return;
135             setHot();
136            
137             Handler[] local;
138             local = _array[1 .. _array.length];
139             foreach(Handler handler; local)
140             {
141                 handler(v1, v2);
142             }
143            
144             if(!_array.length)
145                 return;
146             unsetHot();
147         }
148        
149        
150         ///
151         int opApply(int delegate(Handler) dg)
152         {
153             if(!_array.length)
154                 return 0;
155             setHot();
156            
157             int result = 0;
158            
159             Handler[] local;
160             local = _array[1 .. _array.length];
161             foreach(Handler handler; local)
162             {
163                 result = dg(handler);
164                 if(result)
165                     break;
166             }
167            
168             if(_array.length)
169                 unsetHot();
170            
171             return result;
172         }
173        
174        
175         ///
176         bool hasHandlers() // getter
177         {
178             return _array.length > 1;
179         }
180        
181        
182         // Use opApply and hasHandlers instead.
183         deprecated Handler[] handlers() // getter
184         {
185             if(!hasHandlers)
186                 return null;
187             return _array[1 .. _array.length].dup; // Because _array can be modified. Function is deprecated anyway.
188         }
189        
190        
191         private:
192         Handler[] _array; // Not what it seems.
193        
194        
195         void setHot()
196         {
197             assert(_array.length);
198             _array[0] = cast(Handler)&setHot; // Non-null, GC friendly.
199         }
200        
201        
202         void unsetHot()
203         {
204             assert(_array.length);
205             _array[0] = null;
206         }
207        
208        
209         Handler isHot()
210         {
211             assert(_array.length);
212             return _array[0];
213         }
214        
215        
216         // Thanks to Tomasz "h3r3tic" Stachowiak for his assistance.
217         template _validateHandler(TDG)
218         {
219             static assert(is(TDG == delegate), "DFL: Event handler must be a delegate");
220            
221             alias ParameterTypeTuple!(TDG) TDGParams;
222             static assert(TDGParams.length == 2, "DFL: Event handler needs exactly 2 parameters");
223            
224             static if(is(TDGParams[0] : Object))
225             {
226                 static assert(is(T1: TDGParams[0]), "DFL: Event handler parameter 1 type mismatch");
227             }
228             else
229             {
230                 static assert(is(T1 == TDGParams[0]), "DFL: Event handler parameter 1 type mismatch");
231             }
232            
233             static if(is(TDGParams[1] : Object))
234             {
235                 static assert(is(T2 : TDGParams[1]), "DFL: Event handler parameter 2 type mismatch");
236             }
237             else
238             {
239                 static assert(is(T2 == TDGParams[1]), "DFL: Event handler parameter 2 type mismatch");
240             }
241         }
242     }
243 }
244
245
246 /// Base event arguments.
247 class EventArgs // docmain
248 {
249     /+
250     private static byte[] buf;
251     private import std.gc;
252     
253     
254     new(uint sz)
255     {
256         void* result;
257         
258         // synchronized // Slows it down a lot.
259         {
260             if(sz > buf.length)
261                 buf = new byte[100 + sz];
262             
263             result = buf[0 .. sz];
264             buf = buf[sz .. buf.length];
265         }
266         
267         // std.gc.addRange(result, result + sz); // So that it can contain pointers.
268         return result;
269     }
270     +/
271    
272    
273     /+
274     delete(void* p)
275     {
276         std.gc.removeRange(p);
277     }
278     +/
279    
280    
281     //private static EventArgs _e;
282     private static const EventArgs _e;
283    
284    
285     static this()
286     {
287         _e = new EventArgs;
288     }
289    
290    
291     /// Property: get a reusable, _empty EventArgs.
292     static EventArgs empty() // getter
293     {
294         return _e;
295     }
296 }
297
298
299 // Simple event handler.
300 alias Event!() EventHandler; // deprecated
301
302
303 ///
304 class ThreadExceptionEventArgs: EventArgs
305 {
306     ///
307     // The exception that occured.
308     this(Object theException)
309     {
310         except = theException;
311     }
312    
313    
314     ///
315     final Object exception() // getter
316     {
317         return except;
318     }
319    
320    
321     private:
322     Object except;
323 }
324
325
326 alias Event!(ThreadExceptionEventArgs) ThreadExceptionEventHandler; // deprecated
Note: See TracBrowser for help on using the browser.