Mercurial > hg > orthanc-stone
comparison OrthancStone/Sources/Viewport/WebAssemblyViewport.cpp @ 1512:244ad1e4e76a
reorganization of folders
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 07 Jul 2020 16:21:02 +0200 |
parents | Framework/Viewport/WebAssemblyViewport.cpp@6e43cac7833c |
children | a48ae10857b1 |
comparison
equal
deleted
inserted
replaced
1511:9dfeee74c1e6 | 1512:244ad1e4e76a |
---|---|
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-2020 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 | |
21 | |
22 #include "WebAssemblyViewport.h" | |
23 | |
24 #include "../Toolbox/GenericToolbox.h" | |
25 | |
26 #include <OrthancException.h> | |
27 | |
28 #include <boost/make_shared.hpp> | |
29 #include <boost/enable_shared_from_this.hpp> | |
30 | |
31 namespace OrthancStone | |
32 { | |
33 static void ConvertMouseEvent(PointerEvent& target, | |
34 const EmscriptenMouseEvent& source, | |
35 const ICompositor& compositor) | |
36 { | |
37 int x = static_cast<int>(source.targetX); | |
38 int y = static_cast<int>(source.targetY); | |
39 | |
40 switch (source.button) | |
41 { | |
42 case 0: | |
43 target.SetMouseButton(MouseButton_Left); | |
44 break; | |
45 | |
46 case 1: | |
47 target.SetMouseButton(MouseButton_Middle); | |
48 break; | |
49 | |
50 case 2: | |
51 target.SetMouseButton(MouseButton_Right); | |
52 break; | |
53 | |
54 default: | |
55 target.SetMouseButton(MouseButton_None); | |
56 break; | |
57 } | |
58 | |
59 target.AddPosition(compositor.GetPixelCenterCoordinates(x, y)); | |
60 target.SetAltModifier(source.altKey); | |
61 target.SetControlModifier(source.ctrlKey); | |
62 target.SetShiftModifier(source.shiftKey); | |
63 } | |
64 | |
65 | |
66 class WebAssemblyViewport::WasmLock : public ILock | |
67 { | |
68 private: | |
69 WebAssemblyViewport& that_; | |
70 | |
71 public: | |
72 WasmLock(WebAssemblyViewport& that) : | |
73 that_(that) | |
74 { | |
75 } | |
76 | |
77 virtual bool HasCompositor() const ORTHANC_OVERRIDE | |
78 { | |
79 return that_.compositor_.get() != NULL; | |
80 } | |
81 | |
82 virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE | |
83 { | |
84 if (that_.compositor_.get() == NULL) | |
85 { | |
86 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
87 } | |
88 else | |
89 { | |
90 return *that_.compositor_; | |
91 } | |
92 } | |
93 | |
94 virtual ViewportController& GetController() ORTHANC_OVERRIDE | |
95 { | |
96 assert(that_.controller_); | |
97 return *that_.controller_; | |
98 } | |
99 | |
100 virtual void Invalidate() ORTHANC_OVERRIDE | |
101 { | |
102 that_.Invalidate(); | |
103 } | |
104 }; | |
105 | |
106 | |
107 EM_BOOL WebAssemblyViewport::OnRequestAnimationFrame(double time, void *userData) | |
108 { | |
109 LOG(TRACE) << __func__; | |
110 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData); | |
111 | |
112 if (that->compositor_.get() != NULL && | |
113 that->controller_ /* should always be true */) | |
114 { | |
115 that->Paint(*that->compositor_, *that->controller_); | |
116 } | |
117 | |
118 LOG(TRACE) << "Exiting: " << __func__; | |
119 return true; | |
120 } | |
121 | |
122 EM_BOOL WebAssemblyViewport::OnResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) | |
123 { | |
124 LOG(TRACE) << __func__; | |
125 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData); | |
126 | |
127 if (that->compositor_.get() != NULL) | |
128 { | |
129 that->UpdateSize(*that->compositor_); | |
130 that->Invalidate(); | |
131 } | |
132 | |
133 LOG(TRACE) << "Exiting: " << __func__; | |
134 return true; | |
135 } | |
136 | |
137 | |
138 EM_BOOL WebAssemblyViewport::OnMouseDown(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) | |
139 { | |
140 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData); | |
141 | |
142 LOG(TRACE) << "mouse down: " << that->GetCanvasCssSelector(); | |
143 | |
144 if (that->compositor_.get() != NULL && | |
145 that->interactor_.get() != NULL) | |
146 { | |
147 PointerEvent pointer; | |
148 ConvertMouseEvent(pointer, *mouseEvent, *that->compositor_); | |
149 | |
150 that->controller_->HandleMousePress(*that->interactor_, pointer, | |
151 that->compositor_->GetCanvasWidth(), | |
152 that->compositor_->GetCanvasHeight()); | |
153 that->Invalidate(); | |
154 } | |
155 | |
156 LOG(TRACE) << "Exiting: " << __func__; | |
157 return true; | |
158 } | |
159 | |
160 | |
161 EM_BOOL WebAssemblyViewport::OnMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) | |
162 { | |
163 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData); | |
164 | |
165 if (that->compositor_.get() != NULL && | |
166 that->controller_->HasActiveTracker()) | |
167 { | |
168 PointerEvent pointer; | |
169 ConvertMouseEvent(pointer, *mouseEvent, *that->compositor_); | |
170 if (that->controller_->HandleMouseMove(pointer)) | |
171 { | |
172 that->Invalidate(); | |
173 } | |
174 } | |
175 | |
176 LOG(TRACE) << "Exiting: " << __func__; | |
177 return true; | |
178 } | |
179 | |
180 EM_BOOL WebAssemblyViewport::OnMouseUp(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) | |
181 { | |
182 LOG(TRACE) << __func__; | |
183 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData); | |
184 | |
185 if (that->compositor_.get() != NULL) | |
186 { | |
187 PointerEvent pointer; | |
188 ConvertMouseEvent(pointer, *mouseEvent, *that->compositor_); | |
189 that->controller_->HandleMouseRelease(pointer); | |
190 that->Invalidate(); | |
191 } | |
192 | |
193 LOG(TRACE) << "Exiting: " << __func__; | |
194 return true; | |
195 } | |
196 | |
197 void WebAssemblyViewport::Invalidate() | |
198 { | |
199 emscripten_request_animation_frame(OnRequestAnimationFrame, reinterpret_cast<void*>(this)); | |
200 } | |
201 | |
202 void WebAssemblyViewport::AcquireCompositor(ICompositor* compositor /* takes ownership */) | |
203 { | |
204 if (compositor == NULL) | |
205 { | |
206 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
207 } | |
208 else | |
209 { | |
210 compositor_.reset(compositor); | |
211 } | |
212 } | |
213 | |
214 #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1 | |
215 // everything OK..... we're using the new setting | |
216 #else | |
217 #pragma message("WARNING: DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR is not defined or equal to 0. Stone will use the OLD Emscripten rules for DOM element selection.") | |
218 #endif | |
219 | |
220 WebAssemblyViewport::WebAssemblyViewport( | |
221 const std::string& canvasId, bool enableEmscriptenMouseEvents) : | |
222 canvasId_(canvasId), | |
223 #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1 | |
224 canvasCssSelector_("#" + canvasId), | |
225 #else | |
226 canvasCssSelector_(canvasId), | |
227 #endif | |
228 interactor_(new DefaultViewportInteractor), | |
229 enableEmscriptenMouseEvents_(enableEmscriptenMouseEvents) | |
230 { | |
231 } | |
232 | |
233 void WebAssemblyViewport::PostConstructor() | |
234 { | |
235 boost::shared_ptr<IViewport> viewport = shared_from_this(); | |
236 controller_.reset(new ViewportController(viewport)); | |
237 | |
238 LOG(INFO) << "Initializing Stone viewport on HTML canvas: " | |
239 << canvasId_; | |
240 | |
241 if (canvasId_.empty() || | |
242 canvasId_[0] == '#') | |
243 { | |
244 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, | |
245 "The canvas identifier must not start with '#'"); | |
246 } | |
247 | |
248 // Disable right-click on the canvas (i.e. context menu) | |
249 EM_ASM({ | |
250 document.getElementById(UTF8ToString($0)).oncontextmenu = | |
251 function(event) | |
252 { | |
253 event.preventDefault(); | |
254 } | |
255 }, | |
256 canvasId_.c_str() // $0 | |
257 ); | |
258 | |
259 // It is not possible to monitor the resizing of individual | |
260 // canvas, so we track the full window of the browser | |
261 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, | |
262 reinterpret_cast<void*>(this), | |
263 false, | |
264 OnResize); | |
265 | |
266 if (enableEmscriptenMouseEvents_) | |
267 { | |
268 | |
269 // if any of this function causes an error in the console, please | |
270 // make sure you are using the new (as of 1.39.x) version of | |
271 // emscripten element lookup rules( pass | |
272 // "-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1" to the linker. | |
273 | |
274 emscripten_set_mousedown_callback(canvasCssSelector_.c_str(), | |
275 reinterpret_cast<void*>(this), | |
276 false, | |
277 OnMouseDown); | |
278 | |
279 emscripten_set_mousemove_callback(canvasCssSelector_.c_str(), | |
280 reinterpret_cast<void*>(this), | |
281 false, | |
282 OnMouseMove); | |
283 | |
284 emscripten_set_mouseup_callback(canvasCssSelector_.c_str(), | |
285 reinterpret_cast<void*>(this), | |
286 false, | |
287 OnMouseUp); | |
288 } | |
289 } | |
290 | |
291 void WebAssemblyViewport::UpdateCanvasSize() | |
292 { | |
293 UpdateSize(*compositor_); | |
294 } | |
295 | |
296 WebAssemblyViewport::~WebAssemblyViewport() | |
297 { | |
298 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, | |
299 reinterpret_cast<void*>(this), | |
300 false, | |
301 NULL); | |
302 | |
303 if (enableEmscriptenMouseEvents_) | |
304 { | |
305 | |
306 emscripten_set_mousedown_callback(canvasCssSelector_.c_str(), | |
307 reinterpret_cast<void*>(this), | |
308 false, | |
309 NULL); | |
310 | |
311 emscripten_set_mousemove_callback(canvasCssSelector_.c_str(), | |
312 reinterpret_cast<void*>(this), | |
313 false, | |
314 NULL); | |
315 | |
316 emscripten_set_mouseup_callback(canvasCssSelector_.c_str(), | |
317 reinterpret_cast<void*>(this), | |
318 false, | |
319 NULL); | |
320 } | |
321 } | |
322 | |
323 IViewport::ILock* WebAssemblyViewport::Lock() | |
324 { | |
325 return new WasmLock(*this); | |
326 } | |
327 | |
328 void WebAssemblyViewport::AcquireInteractor(IViewportInteractor* interactor) | |
329 { | |
330 if (interactor == NULL) | |
331 { | |
332 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
333 } | |
334 else | |
335 { | |
336 interactor_.reset(interactor); | |
337 } | |
338 } | |
339 } |