Mercurial > hg > orthanc-stone
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 } |