comparison Applications/Generic/GuiAdapter.h @ 843:67f9c27214c5

Removed extra logging + doc + added GuiAdapter and LockingEmitter
author Benjamin Golinvaux <bgo@osimis.io>
date Fri, 14 Jun 2019 12:14:16 +0200
parents
children cdba0dbb4682
comparison
equal deleted inserted replaced
841:266e2b0b9abc 843:67f9c27214c5
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 #include <string>
21
22 #if ORTHANC_ENABLE_WASM != 1
23 # ifdef __EMSCRIPTEN__
24 # error __EMSCRIPTEN__ is defined and ORTHANC_ENABLE_WASM != 1
25 # endif
26 #endif
27
28 #if ORTHANC_ENABLE_WASM == 1
29 # ifndef __EMSCRIPTEN__
30 # error __EMSCRIPTEN__ is not defined and ORTHANC_ENABLE_WASM == 1
31 # endif
32 #endif
33
34 #if ORTHANC_ENABLE_WASM == 1
35 # include <emscripten/html5.h>
36 #else
37 # if ORTHANC_ENABLE_SDL == 1
38 # include <SDL.h>
39 # endif
40 #endif
41
42 #include "../../Framework/StoneException.h"
43
44 #if ORTHANC_ENABLE_THREADS != 1
45 # include "../../Framework/Messages/LockingEmitter.h"
46 #endif
47
48 #include <boost/shared_ptr.hpp>
49 #include <boost/weak_ptr.hpp>
50
51 namespace OrthancStone
52 {
53
54 /**
55 This interface is used to store the widgets that are controlled by the
56 GuiAdapter and receive event callbacks.
57 The callbacks may possibly be downcast (using dynamic_cast, for safety) \
58 to the actual widget type
59 */
60 class IGuiAdapterWidget
61 {
62 public:
63 virtual ~IGuiAdapterWidget() {}
64 };
65
66 enum GuiAdapterMouseEventType
67 {
68 GUIADAPTER_EVENT_MOUSEDOWN = 1973,
69 GUIADAPTER_EVENT_MOUSEMOVE = 1974,
70 GUIADAPTER_EVENT_MOUSEUP = 1975,
71 GUIADAPTER_EVENT_WHEEL = 1976
72 };
73
74 const unsigned int GUIADAPTER_DELTA_PIXEL = 2973;
75 const unsigned int GUIADAPTER_DELTA_LINE = 2974;
76 const unsigned int GUIADAPTER_DELTA_PAGE = 2975;
77
78 struct GuiAdapterUiEvent;
79 struct GuiAdapterMouseEvent;
80 struct GuiAdapterWheelEvent;
81 struct GuiAdapterKeyboardEvent;
82
83 class LockingEmitter;
84
85 #if 1
86 typedef bool (*OnMouseEventFunc)(const GuiAdapterMouseEvent* mouseEvent, void* userData);
87 typedef bool (*OnMouseWheelFunc)(const GuiAdapterWheelEvent* wheelEvent, void* userData);
88 typedef bool (*OnKeyDownFunc) (const GuiAdapterKeyboardEvent* keyEvent, void* userData);
89 typedef bool (*OnKeyUpFunc) (const GuiAdapterKeyboardEvent* keyEvent, void* userData);
90
91 typedef bool (*OnAnimationFrameFunc)(double time, void* userData);
92 typedef bool (*OnWindowResizeFunc)(const GuiAdapterUiEvent* uiEvent, void* userData);
93
94 #else
95
96 #if ORTHANC_ENABLE_WASM == 1
97 typedef EM_BOOL (*OnMouseEventFunc)(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
98 typedef EM_BOOL (*OnMouseWheelFunc)(int eventType, const EmscriptenWheelEvent* wheelEvent, void* userData);
99 typedef EM_BOOL (*OnKeyDownFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
100 typedef EM_BOOL (*OnKeyUpFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
101
102 typedef EM_BOOL (*OnAnimationFrameFunc)(double time, void* userData);
103 typedef EM_BOOL (*OnWindowResizeFunc)(int eventType, const EmscriptenUiEvent* uiEvent, void* userData);
104 #else
105 typedef bool (*OnMouseEventFunc)(int eventType, const SDL_Event* mouseEvent, void* userData);
106 typedef bool (*OnMouseWheelFunc)(int eventType, const SDL_Event* wheelEvent, void* userData);
107 typedef bool (*OnKeyDownFunc) (int eventType, const SDL_Event* keyEvent, void* userData);
108 typedef bool (*OnKeyUpFunc) (int eventType, const SDL_Event* keyEvent, void* userData);
109
110 typedef bool (*OnAnimationFrameFunc)(double time, void* userData);
111 typedef bool (*OnWindowResizeFunc)(int eventType, const GuiAdapterUiEvent* uiEvent, void* userData);
112 #endif
113
114 #endif
115 struct GuiAdapterMouseEvent {
116 GuiAdapterMouseEventType type;
117 //double timestamp;
118 //long screenX;
119 //long screenY;
120 //long clientX;
121 //long clientY;
122 bool ctrlKey;
123 bool shiftKey;
124 bool altKey;
125 //bool metaKey;
126 unsigned short button;
127 //unsigned short buttons;
128 //long movementX;
129 //long movementY;
130 long targetX;
131 long targetY;
132 // 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)
133 //long canvasX;
134 //long canvasY;
135 //long padding;
136 };
137
138 struct GuiAdapterWheelEvent {
139 GuiAdapterMouseEvent mouse;
140 double deltaX;
141 double deltaY;
142 unsigned long deltaMode;
143 };
144
145 // we don't use any data now
146 struct GuiAdapterUiEvent {};
147
148 // EmscriptenKeyboardEvent
149 struct GuiAdapterKeyboardEvent
150 {
151 bool ctrlKey;
152 bool shiftKey;
153 bool altKey;
154 };
155
156 /*
157 Mousedown event trigger when either the left or right (or middle) mouse is pressed
158 on the object;
159
160 Mouseup event trigger when either the left or right (or middle) mouse is released
161 above the object after triggered mousedown event and held.
162
163 Click event trigger when the only left mouse button is pressed and released on the
164 same object, requires the Mousedown and Mouseup event happened before Click event.
165
166 The normal expect trigger order: onMousedown >> onMouseup >> onClick
167
168 Testing in Chrome v58, the time between onMouseup and onClick events are around
169 7ms to 15ms
170
171 FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/
172 */
173 #if ORTHANC_ENABLE_WASM == 1
174 void ConvertFromPlatform(
175 GuiAdapterUiEvent& dest,
176 int eventType,
177 const EmscriptenUiEvent& src);
178
179 void ConvertFromPlatform(
180 GuiAdapterMouseEvent& dest,
181 int eventType,
182 const EmscriptenMouseEvent& src);
183
184 void ConvertFromPlatform(
185 GuiAdapterWheelEvent& dest,
186 int eventType,
187 const EmscriptenWheelEvent& src);
188
189 void ConvertFromPlatform(
190 GuiAdapterKeyboardEvent& dest,
191 const EmscriptenKeyboardEvent& src);
192
193 #else
194
195 # if ORTHANC_ENABLE_SDL == 1
196 void ConvertFromPlatform(
197 GuiAdapterMouseEvent& dest,
198 bool ctrlPressed, bool shiftPressed, bool altPressed,
199 const SDL_Event& source);
200 # endif
201
202 #endif
203
204 class GuiAdapter
205 {
206 public:
207 #if ORTHANC_ENABLE_THREADS == 1
208 GuiAdapter(LockingEmitter& lockingEmitter) : lockingEmitter_(lockingEmitter)
209 {}
210 #else
211 GuiAdapter() {}
212 #endif
213
214 void RegisterWidget(boost::shared_ptr<IGuiAdapterWidget> widget);
215
216 /**
217 emscripten_set_resize_callback("#window", NULL, false, OnWindowResize);
218
219 emscripten_set_wheel_callback("mycanvas1", widget1_.get(), false, OnMouseWheel);
220 emscripten_set_wheel_callback("mycanvas2", widget2_.get(), false, OnMouseWheel);
221 emscripten_set_wheel_callback("mycanvas3", widget3_.get(), false, OnMouseWheel);
222
223 emscripten_set_keydown_callback("#window", NULL, false, OnKeyDown);
224 emscripten_set_keyup_callback("#window", NULL, false, OnKeyUp);
225
226 emscripten_request_animation_frame_loop(OnAnimationFrame, NULL);
227
228 SDL:
229 see https://wiki.libsdl.org/SDL_CaptureMouse
230
231 */
232
233 void SetMouseDownCallback(std::string canvasId, void* userData, bool capture, OnMouseEventFunc func);
234 void SetMouseMoveCallback(std::string canvasId, void* userData, bool capture, OnMouseEventFunc func);
235 void SetMouseUpCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func);
236 void SetWheelCallback (std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func);
237 void SetKeyDownCallback (std::string canvasId, void* userData, bool capture, OnKeyDownFunc func);
238 void SetKeyUpCallback (std::string canvasId, void* userData, bool capture, OnKeyUpFunc func);
239
240 // if you pass "#window", under SDL, then any Window resize will trigger the callback
241 void SetResizeCallback (std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func);
242
243 void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
244
245 // TODO: implement and call to remove canvases [in SDL, although code should be generic]
246 void SetOnExitCallback();
247
248 // void
249 // OnWindowResize
250 // oracle
251 // broker
252
253 /**
254 Under SDL, this function does NOT return until all windows have been closed.
255 Under wasm, it returns without doing anything, since the event loop is managed
256 by the browser.
257 */
258 void Run();
259
260 #if ORTHANC_ENABLE_WASM != 1
261 /**
262 This method must be called in order for callback handler to be allowed to
263 be registered.
264
265 We'll retrieve its name and use it as the canvas name in all subsequent
266 calls
267 */
268 //void RegisterSdlWindow(SDL_Window* window);
269 //void UnregisterSdlWindow(SDL_Window* window);
270 #endif
271
272 private:
273
274 #if ORTHANC_ENABLE_THREADS == 1
275 /**
276 This object is used by the multithreaded Oracle to serialize access to
277 shared data. We need to use it as soon as we access the state.
278 */
279 LockingEmitter& lockingEmitter_;
280 #endif
281
282 /**
283 In SDL, this executes all the registered headers
284 */
285 void OnAnimationFrame();
286
287 //void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
288 std::vector<std::pair<OnAnimationFrameFunc, void*> >
289 animationFrameHandlers_;
290
291 void OnResize();
292
293 std::vector<std::pair<OnWindowResizeFunc, void*> >
294 resizeHandlers_;
295
296
297 #if ORTHANC_ENABLE_SDL == 1
298
299 /**
300 This executes all the registered headers if needed (in wasm, the browser
301 deals with this)
302 */
303 void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event);
304 #endif
305
306 /**
307 This executes all the registered headers if needed (in wasm, the browser
308 deals with this)
309 */
310 void ViewportsUpdateSize();
311
312 std::vector<boost::weak_ptr<IGuiAdapterWidget>> widgets_;
313
314 template<typename F> void VisitWidgets(F func)
315 {
316 for (auto w : widgets_)
317 {
318 boost::shared_ptr<IGuiAdapterWidget> widget = w.lock();
319 func(widget);
320 }
321 }
322 };
323 }