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 }