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