1 module skia.EventHandler; 2 3 import std.concurrency:initOnce; 4 5 import std.algorithm; 6 import std.container; 7 import std.range; 8 import std.signals; 9 10 11 // 12 // Summary: 13 // Represents the method that will handle an event when the event provides data. 14 // 15 // Parameters: 16 // sender: 17 // The source of the event. 18 // 19 // e: 20 // An object that contains the event data. 21 // 22 // Type parameters: 23 // TEventArgs: 24 // The type of the event data generated by the event. 25 struct EventHandler(T...) 26 { 27 alias void delegate(Object sender, T args) HandlerDelegate; 28 29 mixin Signal!(Object, T); 30 31 void opCall(Object sender, T args) 32 { 33 synchronized 34 { 35 emit(sender, args); 36 } 37 } 38 39 ref EventHandler!(T) opOpAssign(string op, HandlerDelegate)(HandlerDelegate handler) 40 if(op == "+" || op == "-" ) 41 { 42 // BUG: Can't connect delegate which is defined in a function. 43 static if(op == "+") 44 connect(handler); 45 else static if(op == "-") 46 disconnect(handler); 47 else 48 assert(0, op ~ "is not suppported."); 49 return this; 50 } 51 } 52 53 unittest 54 { 55 class Observer 56 { 57 EventHandlerTester tester; 58 int counter; 59 60 this() 61 { 62 tester = new EventHandlerTester(); 63 tester.onClick.connect(&watch01); 64 tester.onClick += &watch02; 65 tester.onMove += &watch03; 66 counter=0; 67 } 68 69 void watch01(Object obj, string msg) 70 { 71 counter++; 72 writeln(counter," running watch01: ", msg); 73 } 74 75 void watch02(Object obj, string msg) 76 { 77 counter++; 78 writeln(counter, " running watch02: ", msg); 79 } 80 81 82 void watch03(Object obj, string msg, int a) 83 { 84 counter++; 85 writeln(counter, " running watch03: ", msg, a); 86 } 87 88 void test() 89 { 90 tester.start(); 91 92 counter=0; 93 //tester.onClick.disconnect(&watch01); // bug: Invalid memory operation 94 //tester.onClick -= &watch02; 95 96 //tester.start(); 97 98 } 99 100 } 101 102 class EventHandlerTester 103 { 104 EventHandler!() onClick1; 105 EventHandler!string onClick; 106 EventHandler!(string, int) onMove; 107 108 this() 109 { 110 } 111 112 void start() 113 { 114 onClick(this, "onClick"); 115 onMove(this, "Move to ", 20); 116 } 117 } 118 119 Observer o = new Observer(); 120 o.test(); 121 } 122 123 124 /** 125 for function 126 */ 127 struct CallbackHandler(T...) 128 { 129 alias void function(T args) HandlerFunction; 130 private HandlerFunction[] m_handler; 131 132 void opCall(T args) 133 { 134 synchronized 135 { 136 for(int i = 0; i < this.m_handler.length; i++) 137 this.m_handler[i](args); 138 // emit(args); 139 } 140 } 141 142 ref CallbackHandler!(T) opOpAssign(string op, HandlerFunction)(HandlerFunction handler) 143 if(op == "+" || op == "-" ) 144 { 145 static if(op == "+") 146 m_handler ~= handler; 147 else static if(op == "-") 148 { 149 size_t len = m_handler.length; 150 for(size_t i=0; i<len; i++) 151 { 152 if(m_handler[i] == handler) 153 { 154 if(i == len -1) 155 m_handler = m_handler[0..i]; 156 else 157 m_handler = m_handler[0..i] ~ m_handler[i+1 .. len]; 158 break; 159 } 160 } 161 } 162 else 163 assert(0, op ~ "is not suppported."); 164 165 return this; 166 } 167 } 168 169 170 /** 171 the base class for classes containing event data. 172 */ 173 class EventArgs 174 { 175 /** 176 Represents an event with no event data. 177 */ 178 static EventArgs Empty() { 179 __gshared EventArgs inst; 180 return initOnce!inst(new EventArgs()); 181 } 182 183 }