1 module unecht.core.events;
2 
3 import unecht.core.component;
4 import unecht.core.types:UESize;
5 public import unecht.glfw.types:UEKey;
6 
7 ///
8 enum UEEventType
9 {
10     updateEditMode,
11 	key,
12 	text,
13 	windowSize,
14 	framebufferSize,
15 	windowFocus,
16     mouseScroll,
17     mouseButton,
18     mousePos,
19     joystickStatus,
20     joystickAxes,
21     joystickButton
22 }
23 
24 ///
25 struct EventModKeys
26 {
27 	private bool shiftDown;
28 	private bool ctrlDown;
29 	private bool altDown;
30 	private bool superDown;
31 
32     void set(bool modShift,bool modCtrl,bool modAlt,bool modSuper) nothrow
33     {
34         shiftDown = modShift;
35         ctrlDown = modCtrl;
36         superDown = modSuper;
37         altDown = modAlt;
38     }
39 
40     ///
41     void setFromBitMaskGLFW(int mask) nothrow
42     {
43         import unecht.core.stdex:testBitMask;
44         import derelict.glfw3.glfw3;
45 
46         shiftDown = testBitMask(mask,GLFW_MOD_SHIFT);
47         ctrlDown = testBitMask(mask,GLFW_MOD_CONTROL);
48         altDown = testBitMask(mask,GLFW_MOD_ALT);
49         superDown = testBitMask(mask,GLFW_MOD_SUPER);
50     }
51 
52 	/// is shift mod set
53 	@property bool isModShift() const { return shiftDown; }
54 	///
55 	@property bool isModCtrl() const { return ctrlDown; }
56 	///
57 	@property bool isModAlt() const { return altDown; }
58 	///
59 	@property bool isModSuper() const { return superDown; }
60 }
61 
62 ///
63 struct UEEvent
64 {
65 	UEEventType eventType;
66 	struct KeyEvent
67 	{
68 		enum Action
69 		{
70 			Down,
71 			Up,
72 			Repeat,
73 		}
74 
75 		UEKey key;
76 		Action action;
77 		EventModKeys mods;
78 	}
79 	KeyEvent keyEvent;
80 
81 	struct TextEvent
82 	{
83 		dchar character;
84         EventModKeys mods;
85 	}
86 	TextEvent textEvent;
87 
88 	struct SizeEvent
89 	{
90 		UESize size;
91 	}
92 	SizeEvent windowSizeEvent;
93 	SizeEvent framebufferSizeEvent;
94 
95 	struct FocusEvent
96 	{
97 		bool gainedFocus;
98 	}
99 	FocusEvent focusEvent;
100 
101     struct MouseScrollEvent
102     {
103         double xoffset;
104         double yoffset;
105         EventModKeys mods;
106     }
107     MouseScrollEvent mouseScrollEvent;
108 
109     struct MouseButtonEvent
110     {
111         enum Action 
112         {
113             down,
114             up,
115             click
116         }
117 
118         int button;
119         Action action;
120         MousePosEvent pos;
121 
122         ///
123         @property bool isDown() const {return action==Action.down;}
124         ///
125         @property bool isClick() const {return action==Action.click;}
126     }
127     MouseButtonEvent mouseButtonEvent;
128 
129     struct MousePosEvent
130     {
131         double x;
132         double y;
133 
134 		EventModKeys mods;
135     }
136     MousePosEvent mousePosEvent;
137 
138     struct JoystickStatus
139     {
140         uint id;
141         string name;
142         uint buttonCount;
143         uint axesCount;
144         bool connected;
145     }
146     JoystickStatus joystickStatus;
147 
148     struct JoystickButton
149     {
150         uint buttonId;
151         bool pressed;
152     }
153     JoystickButton joystickButton;
154 
155     struct JoystickAxes
156     {
157         uint id;
158         float[] axes;
159     }
160     JoystickAxes joystickAxes;
161 }
162 
163 ///
164 alias UEEventCallback = void delegate (UEEvent);
165 
166 ///
167 struct UEEventReceiver
168 {
169 	UEComponent component;
170 	UEEventType eventType;
171 	UEEventCallback eventFunc;
172 
173 	private bool removed=false;
174 }
175 
176 ///
177 interface UEEvents
178 {
179 	///
180 	void register(UEEventReceiver);
181 	///
182 	void unRegister(UEEventReceiver);
183 	///
184 	void removeComponent(UEComponent);
185     ///
186 	//TODO: makes this one only schedule and trigger all events in the main loop (#145)
187     void trigger(UEEvent) nothrow;
188 }
189 
190 ///
191 final class UEEventsSystem : UEEvents
192 {
193 	///
194 	override void register(UEEventReceiver _receiver)
195 	{
196 		receiver ~= _receiver;
197 	}
198 
199 	///
200 	override void unRegister(UEEventReceiver _receiver)
201 	{
202 		foreach(ref r; receiver)
203 		{
204 			if(r.component == _receiver.component && r.eventType == _receiver.eventType)
205 			{
206 				r.removed = true;
207 				dirty = true;
208 			}
209 		}
210 	}
211 
212 	///
213 	override void removeComponent(UEComponent _comp)
214 	{
215 		foreach(ref r; receiver)
216 		{
217 			if(r.component is _comp)
218 			{
219 				r.removed = true;
220 				dirty = true;
221                 r.component = null;
222 			}
223 		}
224 	}
225 
226 	UEEventReceiver[] receiver;
227 	bool dirty=false;
228 
229 	///
230 	override void trigger(UEEvent _ev) nothrow
231 	{
232 		try{
233 			foreach(r; receiver)
234 			{
235 				//TODO: support correct recursive enabled/disabled values 
236 				if(r.removed || (!r.component.enabled) || (!r.component.sceneNode.enabled))
237 					continue;
238 
239 				if(r.eventType == _ev.eventType)
240 				{
241 					r.eventFunc(_ev);
242 				}
243 			}
244 		}
245 		catch(Throwable e){
246 			import unecht.core.logger:log;
247 			try log.errorf("%s",e);
248 			catch(Throwable){}
249 		}
250 	}
251 
252 	/// remove deleted entries
253 	void cleanUp()
254 	{
255 		if(dirty)
256 		{
257 			//TODO:
258 		}
259 
260 		dirty = false;
261 	}
262 }