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