comparison Applications/Generic/GuiAdapter.h @ 860:238693c3bc51 am-dev

merge default -> am-dev
author Alain Mazy <alain@mazy.be>
date Mon, 24 Jun 2019 14:35:00 +0200
parents e3c56d4f863f
children f0bf971a1e31 12b591d5d63c
comparison
equal deleted inserted replaced
856:a6e17a5a39e7 860:238693c3bc51
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2019 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 #pragma once
21
22 #include <string>
23
24 #if ORTHANC_ENABLE_WASM != 1
25 # ifdef __EMSCRIPTEN__
26 # error __EMSCRIPTEN__ is defined and ORTHANC_ENABLE_WASM != 1
27 # endif
28 #endif
29
30 #if ORTHANC_ENABLE_WASM == 1
31 # ifndef __EMSCRIPTEN__
32 # error __EMSCRIPTEN__ is not defined and ORTHANC_ENABLE_WASM == 1
33 # endif
34 #endif
35
36 #if ORTHANC_ENABLE_WASM == 1
37 # include <emscripten/html5.h>
38 #else
39 # if ORTHANC_ENABLE_SDL == 1
40 # include <SDL.h>
41 # endif
42 #endif
43
44 #include "../../Framework/StoneException.h"
45
46 #if ORTHANC_ENABLE_THREADS != 1
47 # include "../../Framework/Messages/LockingEmitter.h"
48 #endif
49
50 #include <vector>
51 #include <boost/shared_ptr.hpp>
52 #include <boost/weak_ptr.hpp>
53
54 namespace OrthancStone
55 {
56
57 /**
58 This interface is used to store the widgets that are controlled by the
59 GuiAdapter and receive event callbacks.
60 The callbacks may possibly be downcast (using dynamic_cast, for safety) \
61 to the actual widget type
62 */
63 class IGuiAdapterWidget
64 {
65 public:
66 virtual ~IGuiAdapterWidget() {}
67
68 };
69
70 enum GuiAdapterMouseEventType
71 {
72 GUIADAPTER_EVENT_MOUSEDOWN = 1973,
73 GUIADAPTER_EVENT_MOUSEMOVE = 1974,
74 GUIADAPTER_EVENT_MOUSEUP = 1975,
75 GUIADAPTER_EVENT_WHEEL = 1976
76 };
77
78 const unsigned int GUIADAPTER_DELTA_PIXEL = 2973;
79 const unsigned int GUIADAPTER_DELTA_LINE = 2974;
80 const unsigned int GUIADAPTER_DELTA_PAGE = 2975;
81
82 struct GuiAdapterUiEvent;
83 struct GuiAdapterMouseEvent;
84 struct GuiAdapterWheelEvent;
85 struct GuiAdapterKeyboardEvent;
86
87 class LockingEmitter;
88
89 #if 1
90 typedef bool (*OnMouseEventFunc)(std::string canvasId, const GuiAdapterMouseEvent* mouseEvent, void* userData);
91 typedef bool (*OnMouseWheelFunc)(std::string canvasId, const GuiAdapterWheelEvent* wheelEvent, void* userData);
92 typedef bool (*OnKeyDownFunc) (std::string canvasId, const GuiAdapterKeyboardEvent* keyEvent, void* userData);
93 typedef bool (*OnKeyUpFunc) (std::string canvasId, const GuiAdapterKeyboardEvent* keyEvent, void* userData);
94
95 typedef bool (*OnAnimationFrameFunc)(double time, void* userData);
96 typedef bool (*OnWindowResizeFunc)(std::string canvasId, const GuiAdapterUiEvent* uiEvent, void* userData);
97
98 #else
99
100 #if ORTHANC_ENABLE_WASM == 1
101 typedef EM_BOOL (*OnMouseEventFunc)(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
102 typedef EM_BOOL (*OnMouseWheelFunc)(int eventType, const EmscriptenWheelEvent* wheelEvent, void* userData);
103 typedef EM_BOOL (*OnKeyDownFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
104 typedef EM_BOOL (*OnKeyUpFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
105
106 typedef EM_BOOL (*OnAnimationFrameFunc)(double time, void* userData);
107 typedef EM_BOOL (*OnWindowResizeFunc)(int eventType, const EmscriptenUiEvent* uiEvent, void* userData);
108 #else
109 typedef bool (*OnMouseEventFunc)(int eventType, const SDL_Event* mouseEvent, void* userData);
110 typedef bool (*OnMouseWheelFunc)(int eventType, const SDL_Event* wheelEvent, void* userData);
111 typedef bool (*OnKeyDownFunc) (int eventType, const SDL_Event* keyEvent, void* userData);
112 typedef bool (*OnKeyUpFunc) (int eventType, const SDL_Event* keyEvent, void* userData);
113
114 typedef bool (*OnAnimationFrameFunc)(double time, void* userData);
115 typedef bool (*OnWindowResizeFunc)(int eventType, const GuiAdapterUiEvent* uiEvent, void* userData);
116 #endif
117
118 #endif
119 struct GuiAdapterMouseEvent {
120 GuiAdapterMouseEventType type;
121 //double timestamp;
122 //long screenX;
123 //long screenY;
124 //long clientX;
125 //long clientY;
126 bool ctrlKey;
127 bool shiftKey;
128 bool altKey;
129 //bool metaKey;
130 unsigned short button;
131 //unsigned short buttons;
132 //long movementX;
133 //long movementY;
134 long targetX;
135 long targetY;
136 // canvasX and canvasY are deprecated - there no longer exists a Module['canvas'] object, so canvasX/Y are no longer reported (register a listener on canvas directly to get canvas coordinates, or translate manually)
137 //long canvasX;
138 //long canvasY;
139 //long padding;
140 };
141
142 struct GuiAdapterWheelEvent {
143 GuiAdapterMouseEvent mouse;
144 double deltaX;
145 double deltaY;
146 unsigned long deltaMode;
147 };
148
149 // we don't use any data now
150 struct GuiAdapterUiEvent {};
151
152 // EmscriptenKeyboardEvent
153 struct GuiAdapterKeyboardEvent
154 {
155 bool ctrlKey;
156 bool shiftKey;
157 bool altKey;
158 };
159
160 std::ostream& operator<<(std::ostream& os, const GuiAdapterKeyboardEvent& event);
161
162 /*
163 Mousedown event trigger when either the left or right (or middle) mouse is pressed
164 on the object;
165
166 Mouseup event trigger when either the left or right (or middle) mouse is released
167 above the object after triggered mousedown event and held.
168
169 Click event trigger when the only left mouse button is pressed and released on the
170 same object, requires the Mousedown and Mouseup event happened before Click event.
171
172 The normal expect trigger order: onMousedown >> onMouseup >> onClick
173
174 Testing in Chrome v58, the time between onMouseup and onClick events are around
175 7ms to 15ms
176
177 FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/
178 */
179 #if ORTHANC_ENABLE_WASM == 1
180 void ConvertFromPlatform(
181 GuiAdapterUiEvent& dest,
182 int eventType,
183 const EmscriptenUiEvent& src);
184
185 void ConvertFromPlatform(
186 GuiAdapterMouseEvent& dest,
187 int eventType,
188 const EmscriptenMouseEvent& src);
189
190 void ConvertFromPlatform(
191 GuiAdapterWheelEvent& dest,
192 int eventType,
193 const EmscriptenWheelEvent& src);
194
195 void ConvertFromPlatform(
196 GuiAdapterKeyboardEvent& dest,
197 const EmscriptenKeyboardEvent& src);
198
199 #else
200
201 # if ORTHANC_ENABLE_SDL == 1
202 void ConvertFromPlatform(
203 GuiAdapterMouseEvent& dest,
204 bool ctrlPressed, bool shiftPressed, bool altPressed,
205 const SDL_Event& source);
206
207 void ConvertFromPlatform(
208 GuiAdapterWheelEvent& dest,
209 bool ctrlPressed, bool shiftPressed, bool altPressed,
210 const SDL_Event& source);
211
212 # endif
213
214 #endif
215
216 class GuiAdapter
217 {
218 public:
219 #if ORTHANC_ENABLE_THREADS == 1
220 GuiAdapter(LockingEmitter& lockingEmitter) : lockingEmitter_(lockingEmitter)
221 #else
222 GuiAdapter()
223 #endif
224 {
225 static int instanceCount = 0;
226 ORTHANC_ASSERT(instanceCount == 0);
227 instanceCount = 1;
228 }
229
230 void RegisterWidget(boost::shared_ptr<IGuiAdapterWidget> widget);
231
232 /**
233 emscripten_set_resize_callback("#window", NULL, false, OnWindowResize);
234
235 emscripten_set_wheel_callback("mycanvas1", widget1_.get(), false, OnXXXMouseWheel);
236 emscripten_set_wheel_callback("mycanvas2", widget2_.get(), false, OnXXXMouseWheel);
237 emscripten_set_wheel_callback("mycanvas3", widget3_.get(), false, OnXXXMouseWheel);
238
239 emscripten_set_keydown_callback("#window", NULL, false, OnKeyDown);
240 emscripten_set_keyup_callback("#window", NULL, false, OnKeyUp);
241
242 emscripten_request_animation_frame_loop(OnAnimationFrame, NULL);
243
244 SDL:
245 see https://wiki.libsdl.org/SDL_CaptureMouse
246
247 */
248
249 void SetMouseDownCallback(std::string canvasId, void* userData, bool capture, OnMouseEventFunc func);
250 void SetMouseMoveCallback(std::string canvasId, void* userData, bool capture, OnMouseEventFunc func);
251 void SetMouseUpCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func);
252 void SetWheelCallback (std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func);
253 void SetKeyDownCallback (std::string canvasId, void* userData, bool capture, OnKeyDownFunc func);
254 void SetKeyUpCallback (std::string canvasId, void* userData, bool capture, OnKeyUpFunc func);
255
256 // if you pass "#window", under SDL, then any Window resize will trigger the callback
257 void SetResizeCallback (std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func);
258
259 void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
260
261 // TODO: implement and call to remove canvases [in SDL, although code should be generic]
262 void SetOnExitCallback();
263
264 // void
265 // OnWindowResize
266 // oracle
267 // broker
268
269 /**
270 Under SDL, this function does NOT return until all windows have been closed.
271 Under wasm, it returns without doing anything, since the event loop is managed
272 by the browser.
273 */
274 void Run();
275
276 #if ORTHANC_ENABLE_WASM != 1
277 /**
278 This method must be called in order for callback handler to be allowed to
279 be registered.
280
281 We'll retrieve its name and use it as the canvas name in all subsequent
282 calls
283 */
284 //void RegisterSdlWindow(SDL_Window* window);
285 //void UnregisterSdlWindow(SDL_Window* window);
286 #endif
287
288 private:
289
290 #if ORTHANC_ENABLE_THREADS == 1
291 /**
292 This object is used by the multithreaded Oracle to serialize access to
293 shared data. We need to use it as soon as we access the state.
294 */
295 LockingEmitter& lockingEmitter_;
296 #endif
297
298 /**
299 In SDL, this executes all the registered headers
300 */
301 void OnAnimationFrame();
302
303 //void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
304 std::vector<std::pair<OnAnimationFrameFunc, void*> >
305 animationFrameHandlers_;
306
307 void OnResize();
308
309 #if ORTHANC_ENABLE_SDL == 1
310 template<typename Func>
311 struct EventHandlerData
312 {
313 EventHandlerData(std::string canvasName, Func func, void* userData)
314 : canvasName(canvasName)
315 , func(func)
316 , userData(userData)
317 {
318 }
319
320 std::string canvasName;
321 Func func;
322 void* userData;
323 };
324 std::vector<EventHandlerData<OnWindowResizeFunc> > resizeHandlers_;
325 std::vector<EventHandlerData<OnMouseEventFunc > > mouseDownHandlers_;
326 std::vector<EventHandlerData<OnMouseEventFunc > > mouseMoveHandlers_;
327 std::vector<EventHandlerData<OnMouseEventFunc > > mouseUpHandlers_;
328 std::vector<EventHandlerData<OnMouseWheelFunc > > mouseWheelHandlers_;
329
330
331 /**
332 This executes all the registered headers if needed (in wasm, the browser
333 deals with this)
334 */
335 void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event);
336
337 /**
338 Same remark as OnMouseEvent
339 */
340 void OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event);
341
342 boost::shared_ptr<IGuiAdapterWidget> GetWidgetFromWindowId();
343
344 #endif
345
346 /**
347 This executes all the registered headers if needed (in wasm, the browser
348 deals with this)
349 */
350 void ViewportsUpdateSize();
351
352 std::vector<boost::weak_ptr<IGuiAdapterWidget> > widgets_;
353
354 template<typename F> void VisitWidgets(F func)
355 {
356 for (size_t i = 0; i < widgets_.size(); i++)
357 {
358 boost::shared_ptr<IGuiAdapterWidget> widget = widgets_[i].lock();
359 func(widget);
360 }
361 }
362 };
363 }