comparison Applications/Generic/GuiAdapter.cpp @ 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
21 #include "GuiAdapter.h"
22
23 #if ORTHANC_ENABLE_SDL == 1
24 # if ORTHANC_ENABLE_OPENGL == 1
25 # include "../../Framework/OpenGL/OpenGLIncludes.h"
26 # include <SDL_video.h>
27 # include <SDL_render.h>
28 # include <SDL.h>
29 # endif
30 #endif
31
32 #if ORTHANC_ENABLE_THREADS == 1
33 # include "../../Framework/Messages/LockingEmitter.h"
34 #endif
35
36 namespace OrthancStone
37 {
38 void GuiAdapter::RegisterWidget(boost::shared_ptr<IGuiAdapterWidget> widget)
39 {
40 widgets_.push_back(widget);
41 }
42
43 #if ORTHANC_ENABLE_WASM == 1
44 void GuiAdapter::Run()
45 {
46 }
47
48 void ConvertFromPlatform(
49 GuiAdapterUiEvent& dest,
50 int eventType,
51 const EmscriptenUiEvent& src)
52 {
53 // no data for now
54 }
55
56 void ConvertFromPlatform(
57 GuiAdapterMouseEvent& dest,
58 int eventType,
59 const EmscriptenMouseEvent& src)
60 {
61 memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
62 switch (eventType)
63 {
64 case EMSCRIPTEN_EVENT_CLICK:
65 LOG(ERROR) << "Emscripten EMSCRIPTEN_EVENT_CLICK is not supported";
66 ORTHANC_ASSERT(false, "Not supported");
67 break;
68 case EMSCRIPTEN_EVENT_MOUSEDOWN:
69 dest.type = GUIADAPTER_EVENT_MOUSEDOWN;
70 break;
71 case EMSCRIPTEN_EVENT_MOUSEMOVE:
72 dest.type = GUIADAPTER_EVENT_MOUSEMOVE;
73 break;
74 case EMSCRIPTEN_EVENT_MOUSEUP:
75 dest.type = GUIADAPTER_EVENT_MOUSEUP;
76 break;
77 case EMSCRIPTEN_EVENT_WHEEL:
78 dest.type = GUIADAPTER_EVENT_WHEEL;
79 break;
80
81 default:
82 LOG(ERROR) << "Emscripten event: " << eventType << " is not supported";
83 ORTHANC_ASSERT(false, "Not supported");
84 }
85 //dest.timestamp = src.timestamp;
86 //dest.screenX = src.screenX;
87 //dest.screenY = src.screenY;
88 //dest.clientX = src.clientX;
89 //dest.clientY = src.clientY;
90 dest.ctrlKey = src.ctrlKey;
91 dest.shiftKey = src.shiftKey;
92 dest.altKey = src.altKey;
93 //dest.metaKey = src.metaKey;
94 dest.button = src.button;
95 //dest.buttons = src.buttons;
96 //dest.movementX = src.movementX;
97 //dest.movementY = src.movementY;
98 dest.targetX = src.targetX;
99 dest.targetY = src.targetY;
100 //dest.canvasX = src.canvasX;
101 //dest.canvasY = src.canvasY;
102 //dest.padding = src.padding;
103 }
104
105 void ConvertFromPlatform(
106 GuiAdapterWheelEvent& dest,
107 int eventType,
108 const EmscriptenWheelEvent& src)
109 {
110 ConvertFromPlatform(dest.mouse, eventType, src.mouse);
111 dest.deltaX = src.deltaX;
112 dest.deltaY = src.deltaY;
113 switch (src.deltaMode)
114 {
115 case DOM_DELTA_PIXEL:
116 dest.deltaMode = GUIADAPTER_DELTA_PIXEL;
117 break;
118 case DOM_DELTA_LINE:
119 dest.deltaMode = GUIADAPTER_DELTA_LINE;
120 break;
121 case DOM_DELTA_PAGE:
122 dest.deltaMode = GUIADAPTER_DELTA_PAGE;
123 break;
124 default:
125 ORTHANC_ASSERT(false, "Unknown deltaMode: " << src.deltaMode <<
126 " in wheel event...");
127 }
128 dest.deltaMode = src.deltaMode;
129 }
130
131 void ConvertFromPlatform(
132 GuiAdapterKeyboardEvent& dest,
133 const EmscriptenKeyboardEvent& src)
134 {
135 dest.ctrlKey = src.ctrlKey;
136 dest.shiftKey = src.shiftKey;
137 dest.altKey = src.altKey;
138 }
139
140 template<typename GenericFunc>
141 struct FuncAdapterPayload
142 {
143 void* userData;
144 GenericFunc callback;
145 };
146
147 template<typename GenericFunc,
148 typename GuiAdapterEvent,
149 typename EmscriptenEvent>
150 EM_BOOL OnEventAdapterFunc(
151 int eventType, const EmscriptenEvent* wheelEvent, void* userData)
152 {
153
154 // userData is OnMouseWheelFuncAdapterPayload
155 FuncAdapterPayload<GenericFunc>* payload =
156 reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
157 // LOG(INFO) << "OnEventAdapterFunc";
158 // LOG(INFO) << "------------------";
159 // LOG(INFO) << "eventType: " << eventType << " wheelEvent: " <<
160 // (int)wheelEvent << " userData: " << userData <<
161 // " payload->userData: " << payload->userData;
162
163 GuiAdapterEvent guiEvent;
164 ConvertFromPlatform(guiEvent, eventType, *wheelEvent);
165 bool ret = (*(payload->callback))(&guiEvent, payload->userData);
166 return static_cast<EM_BOOL>(ret);
167 }
168
169 template<typename GenericFunc,
170 typename GuiAdapterEvent,
171 typename EmscriptenEvent>
172 EM_BOOL OnEventAdapterFunc2(
173 int /*eventType*/, const EmscriptenEvent* wheelEvent, void* userData)
174 {
175 // userData is OnMouseWheelFuncAdapterPayload
176 FuncAdapterPayload<GenericFunc>* payload =
177 reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
178
179 GuiAdapterEvent guiEvent;
180 ConvertFromPlatform(guiEvent, *wheelEvent);
181 bool ret = (*(payload->callback))(&guiEvent, payload->userData);
182 return static_cast<EM_BOOL>(ret);
183 }
184
185 template<typename GenericFunc>
186 EM_BOOL OnEventAdapterFunc3(
187 double time, void* userData)
188 {
189 // userData is OnMouseWheelFuncAdapterPayload
190 FuncAdapterPayload<GenericFunc>* payload =
191 reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
192 //std::auto_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload);
193 bool ret = (*(payload->callback))(time, payload->userData);
194 return static_cast<EM_BOOL>(ret);
195 }
196
197 // resize: (const char* target, void* userData, EM_BOOL useCapture, em_ui_callback_func callback)
198 template<
199 typename GenericFunc,
200 typename GuiAdapterEvent,
201 typename EmscriptenEvent,
202 typename EmscriptenSetCallbackFunc>
203 static void SetCallback(
204 EmscriptenSetCallbackFunc emFunc,
205 std::string canvasId, void* userData, bool capture, GenericFunc func)
206 {
207 // TODO: write RemoveCallback with an int id that gets returned from
208 // here
209 FuncAdapterPayload<GenericFunc>* payload =
210 new FuncAdapterPayload<GenericFunc>();
211 std::auto_ptr<FuncAdapterPayload<GenericFunc> > payloadP(payload);
212 payload->callback = func;
213 payload->userData = userData;
214 void* userDataRaw = reinterpret_cast<void*>(payload);
215 // LOG(INFO) << "SetCallback -- userDataRaw: " << userDataRaw <<
216 // " payload: " << payload << " payload->userData: " << payload->userData;
217 (*emFunc)(
218 canvasId.c_str(),
219 userDataRaw,
220 static_cast<EM_BOOL>(capture),
221 &OnEventAdapterFunc<GenericFunc, GuiAdapterEvent, EmscriptenEvent>,
222 EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD);
223 payloadP.release();
224 }
225
226 template<
227 typename GenericFunc,
228 typename GuiAdapterEvent,
229 typename EmscriptenEvent,
230 typename EmscriptenSetCallbackFunc>
231 static void SetCallback2(
232 EmscriptenSetCallbackFunc emFunc,
233 std::string canvasId, void* userData, bool capture, GenericFunc func)
234 {
235 std::auto_ptr<FuncAdapterPayload<GenericFunc> > payload(
236 new FuncAdapterPayload<GenericFunc>()
237 );
238 payload->callback = func;
239 payload->userData = userData;
240 void* userDataRaw = reinterpret_cast<void*>(payload.release());
241 (*emFunc)(
242 canvasId.c_str(),
243 userDataRaw,
244 static_cast<EM_BOOL>(capture),
245 &OnEventAdapterFunc2<GenericFunc, GuiAdapterEvent, EmscriptenEvent>,
246 EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD);
247 }
248
249 template<
250 typename GenericFunc,
251 typename EmscriptenSetCallbackFunc>
252 static void SetCallback3(
253 EmscriptenSetCallbackFunc emFunc,
254 void* userData, GenericFunc func)
255 {
256 // LOG(ERROR) << "SetCallback3 !!!!!! (RequestAnimationFrame)";
257 std::auto_ptr<FuncAdapterPayload<GenericFunc> > payload(
258 new FuncAdapterPayload<GenericFunc>()
259 );
260 payload->callback = func;
261 payload->userData = userData;
262 void* userDataRaw = reinterpret_cast<void*>(payload.release());
263 (*emFunc)(
264 &OnEventAdapterFunc3<GenericFunc>,
265 userDataRaw);
266 }
267
268 void GuiAdapter::SetWheelCallback(
269 std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func)
270 {
271 SetCallback<OnMouseWheelFunc, GuiAdapterWheelEvent, EmscriptenWheelEvent>(
272 &emscripten_set_wheel_callback_on_thread,
273 canvasId,
274 userData,
275 capture,
276 func);
277 }
278
279 void GuiAdapter::SetMouseDownCallback(
280 std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
281 {
282 SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
283 &emscripten_set_mousedown_callback_on_thread,
284 canvasId,
285 userData,
286 capture,
287 func);
288 }
289
290 void GuiAdapter::SetMouseMoveCallback(
291 std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
292 {
293 // LOG(INFO) << "SetMouseMoveCallback -- " << "supplied userData: " <<
294 // userData;
295
296 SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
297 &emscripten_set_mousemove_callback_on_thread,
298 canvasId,
299 userData,
300 capture,
301 func);
302 }
303
304 void GuiAdapter::SetMouseUpCallback(
305 std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
306 {
307 SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
308 &emscripten_set_mouseup_callback_on_thread,
309 canvasId,
310 userData,
311 capture,
312 func);
313 }
314
315 void GuiAdapter::SetKeyDownCallback(
316 std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
317 {
318 SetCallback2<OnKeyDownFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>(
319 &emscripten_set_keydown_callback_on_thread,
320 canvasId,
321 userData,
322 capture,
323 func);
324 }
325
326 void GuiAdapter::SetKeyUpCallback(
327 std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
328 {
329 SetCallback2<OnKeyUpFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>(
330 &emscripten_set_keyup_callback_on_thread,
331 canvasId,
332 userData,
333 capture,
334 func);
335 }
336
337 void GuiAdapter::SetResizeCallback(
338 std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
339 {
340 SetCallback<OnWindowResizeFunc, GuiAdapterUiEvent, EmscriptenUiEvent>(
341 &emscripten_set_resize_callback_on_thread,
342 canvasId,
343 userData,
344 capture,
345 func);
346 }
347
348 void GuiAdapter::RequestAnimationFrame(
349 OnAnimationFrameFunc func, void* userData)
350 {
351 // LOG(ERROR) << "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+";
352 // LOG(ERROR) << "RequestAnimationFrame";
353 // LOG(ERROR) << "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+";
354 SetCallback3<OnAnimationFrameFunc>(
355 &emscripten_request_animation_frame_loop,
356 userData,
357 func);
358 }
359
360 #if 0
361 void GuiAdapter::SetKeyDownCallback(
362 std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
363 {
364 emscripten_set_keydown_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
365 }
366 void GuiAdapter::SetKeyUpCallback(
367 std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
368 {
369 emscripten_set_keyup_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
370 }
371
372 void GuiAdapter::SetResizeCallback(std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
373 {
374 emscripten_set_resize_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
375 }
376
377 void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
378 {
379 emscripten_request_animation_frame_loop(func, userData);
380 }
381 #endif
382
383
384 #else
385
386 void ConvertFromPlatform(
387 GuiAdapterMouseEvent& dest,
388 bool ctrlPressed, bool shiftPressed, bool altPressed,
389 const SDL_Event& source)
390 {
391 memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
392 switch (source.type)
393 {
394 case SDL_MOUSEBUTTONDOWN:
395 dest.type = GUIADAPTER_EVENT_MOUSEDOWN;
396 break;
397 case SDL_MOUSEMOTION:
398 dest.type = GUIADAPTER_EVENT_MOUSEMOVE;
399 break;
400 case SDL_MOUSEBUTTONUP:
401 dest.type = GUIADAPTER_EVENT_MOUSEUP;
402 break;
403 default:
404 LOG(ERROR) << "SDL event: " << source.type << " is not supported";
405 ORTHANC_ASSERT(false, "Not supported");
406 }
407 //dest.timestamp = src.timestamp;
408 //dest.screenX = src.screenX;
409 //dest.screenY = src.screenY;
410 //dest.clientX = src.clientX;
411 //dest.clientY = src.clientY;
412 dest.ctrlKey = ctrlPressed;
413 dest.shiftKey = shiftPressed;
414 dest.altKey = altPressed;
415 //dest.metaKey = src.metaKey;
416 switch (source.button.button)
417 {
418 case SDL_BUTTON_MIDDLE:
419 dest.button = 1;
420 break;
421
422 case SDL_BUTTON_RIGHT:
423 dest.button = 2;
424 break;
425
426 case SDL_BUTTON_LEFT:
427 dest.button = 0;
428 break;
429
430 default:
431 break;
432 }
433 //dest.buttons = src.buttons;
434 //dest.movementX = src.movementX;
435 //dest.movementY = src.movementY;
436 dest.targetX = source.button.x;
437 dest.targetY = source.button.y;
438 //dest.canvasX = src.canvasX;
439 //dest.canvasY = src.canvasY;
440 //dest.padding = src.padding;
441 }
442
443 void GuiAdapter::SetResizeCallback(
444 std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
445 {
446 resizeHandlers_.push_back(std::make_pair(func, userData));
447 }
448
449 void GuiAdapter::SetMouseDownCallback(
450 std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
451 {
452 }
453
454 void GuiAdapter::SetMouseMoveCallback(
455 std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
456 {
457 }
458
459 void GuiAdapter::SetMouseUpCallback(
460 std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
461 {
462 }
463
464 void GuiAdapter::SetWheelCallback(
465 std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func)
466 {
467 }
468
469 void GuiAdapter::SetKeyDownCallback(
470 std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
471 {
472 }
473
474 void GuiAdapter::SetKeyUpCallback(
475 std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
476 {
477 }
478
479
480 void GuiAdapter::OnAnimationFrame()
481 {
482 for (const auto& handler : animationFrameHandlers_)
483 {
484 // TODO: fix time
485 (*(handler.first))(0,handler.second);
486 }
487 }
488
489 void GuiAdapter::OnResize()
490 {
491 for (const auto& handler : resizeHandlers_)
492 {
493 // TODO: fix time
494 (*(handler.first))(0, handler.second);
495 }
496 }
497
498 void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event)
499 {
500 }
501
502
503 void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
504 {
505 animationFrameHandlers_.push_back(std::make_pair(func, userData));
506 }
507
508 # if ORTHANC_ENABLE_OPENGL == 1
509
510 static void GLAPIENTRY
511 OpenGLMessageCallback(GLenum source,
512 GLenum type,
513 GLuint id,
514 GLenum severity,
515 GLsizei length,
516 const GLchar* message,
517 const void* userParam)
518 {
519 if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
520 {
521 fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
522 (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
523 type, severity, message);
524 }
525 }
526 # endif
527
528 void GuiAdapter::Run()
529 {
530 # if ORTHANC_ENABLE_OPENGL == 1
531 glEnable(GL_DEBUG_OUTPUT);
532 glDebugMessageCallback(OpenGLMessageCallback, 0);
533 # endif
534
535 // Uint32 SDL_GetWindowID(SDL_Window* window)
536 // SDL_Window* SDL_GetWindowFromID(Uint32 id) // may return NULL
537
538 bool stop = false;
539 while (!stop)
540 {
541 {
542 LockingEmitter::WriterLock lock(lockingEmitter_);
543 OnAnimationFrame(); // in SDL we must call it
544 }
545
546 SDL_Event event;
547
548 while (!stop && SDL_PollEvent(&event))
549 {
550 LockingEmitter::WriterLock lock(lockingEmitter_);
551
552 if (event.type == SDL_QUIT)
553 {
554 // TODO: call exit callbacks here
555 stop = true;
556 break;
557 }
558 else if ( (event.type == SDL_MOUSEMOTION) ||
559 (event.type == SDL_MOUSEBUTTONDOWN) ||
560 (event.type == SDL_MOUSEBUTTONUP) )
561 {
562 int scancodeCount = 0;
563 const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
564 bool ctrlPressed(false);
565 bool shiftPressed(false);
566 bool altPressed(false);
567
568 if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL])
569 ctrlPressed = true;
570 if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL])
571 ctrlPressed = true;
572 if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT])
573 shiftPressed = true;
574 if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT])
575 shiftPressed = true;
576 if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT])
577 altPressed = true;
578
579 GuiAdapterMouseEvent dest;
580 ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, event);
581 OnMouseEvent(event.window.windowID, dest);
582 #if 0
583 // for reference, how to create trackers
584 if (tracker)
585 {
586 PointerEvent e;
587 e.AddPosition(compositor.GetPixelCenterCoordinates(
588 event.button.x, event.button.y));
589 tracker->PointerMove(e);
590 }
591 #endif
592 }
593 else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
594 {
595 #if 0
596 tracker.reset();
597 #endif
598 OnResize();
599 }
600 else if (event.type == SDL_KEYDOWN && event.key.repeat == 0 /* Ignore key bounce */)
601 {
602 switch (event.key.keysym.sym)
603 {
604 case SDLK_f:
605 // window.GetWindow().ToggleMaximize(); //TODO: move to particular handler
606 break;
607
608 case SDLK_s:
609 #if 0
610 // TODO: re-enable at application-level!!!!
611 VisitWidgets(
612 [](auto value)
613 {
614 auto widget = boost::dynamic_pointer_cast<VolumeSlicerWidget()
615 value->FitContent();
616 });
617 #endif
618 break;
619
620 case SDLK_q:
621 stop = true;
622 break;
623
624 default:
625 break;
626 }
627 }
628 // HandleApplicationEvent(controller, compositor, event, tracker);
629 }
630
631 SDL_Delay(1);
632 }
633 }
634 #endif
635 }
636