Mercurial > hg > orthanc-stone
changeset 1502:e5729dab3f67
moving Deprecated/Applications/Generic/GuiAdapter.[cpp|h] to Framework/Deprecated/
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 30 Jun 2020 11:37:34 +0200 |
parents | 1e381f2596d3 |
children | 553084468225 |
files | Deprecated/Applications/Generic/GuiAdapter.cpp Deprecated/Applications/Generic/GuiAdapter.h Framework/Deprecated/GuiAdapter.cpp Framework/Deprecated/GuiAdapter.h Resources/CMake/OrthancStoneConfiguration.cmake |
diffstat | 5 files changed, 1518 insertions(+), 1526 deletions(-) [+] |
line wrap: on
line diff
--- a/Deprecated/Applications/Generic/GuiAdapter.cpp Tue Jun 30 11:29:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1143 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - -#include "GuiAdapter.h" - -#if ORTHANC_ENABLE_OPENGL == 1 -# include "../../../Framework/OpenGL/OpenGLIncludes.h" -#endif - -#if ORTHANC_ENABLE_SDL == 1 -# include <SDL_video.h> -# include <SDL_render.h> -# include <SDL.h> -#endif - -#if ORTHANC_ENABLE_THREADS == 1 -# include "../../../Framework/Deprecated/Messages/LockingEmitter.h" -#endif - -#include <Compatibility.h> - -namespace OrthancStone -{ - std::ostream& operator<<( - std::ostream& os, const GuiAdapterKeyboardEvent& event) - { - os << "sym: " << event.sym << " (" << (int)(event.sym[0]) << ") ctrl: " << event.ctrlKey << ", " << - "shift: " << event.shiftKey << ", " << - "alt: " << event.altKey; - return os; - } - - std::ostream& operator<<( - std::ostream& os, const GuiAdapterMouseEvent& event) - { - os << "targetX: " << event.targetX << " targetY: " << event.targetY << " button: " << event.button - << "ctrlKey: " << event.ctrlKey << "shiftKey: " << event.shiftKey << "altKey: " << event.altKey; - - return os; - } - - int GuiAdapter::s_instanceCount = 0; - -#if ORTHANC_ENABLE_WASM == 1 - void GuiAdapter::Run(GuiAdapterRunFunc /*func*/, void* /*cookie*/) - { - } - - void ConvertFromPlatform( - GuiAdapterUiEvent& dest, - int eventType, - const EmscriptenUiEvent& src) - { - // no data for now - } - - void ConvertFromPlatform( - GuiAdapterMouseEvent& dest, - int eventType, - const EmscriptenMouseEvent& src) - { - memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); - switch (eventType) - { - case EMSCRIPTEN_EVENT_CLICK: - LOG(ERROR) << "Emscripten EMSCRIPTEN_EVENT_CLICK is not supported"; - ORTHANC_ASSERT(false, "Not supported"); - break; - case EMSCRIPTEN_EVENT_MOUSEDOWN: - dest.type = GUIADAPTER_EVENT_MOUSEDOWN; - break; - case EMSCRIPTEN_EVENT_DBLCLICK: - dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK; - break; - case EMSCRIPTEN_EVENT_MOUSEMOVE: - dest.type = GUIADAPTER_EVENT_MOUSEMOVE; - break; - case EMSCRIPTEN_EVENT_MOUSEUP: - dest.type = GUIADAPTER_EVENT_MOUSEUP; - break; - case EMSCRIPTEN_EVENT_WHEEL: - dest.type = GUIADAPTER_EVENT_WHEEL; - break; - - default: - LOG(ERROR) << "Emscripten event: " << eventType << " is not supported"; - ORTHANC_ASSERT(false, "Not supported"); - } - //dest.timestamp = src.timestamp; - //dest.screenX = src.screenX; - //dest.screenY = src.screenY; - //dest.clientX = src.clientX; - //dest.clientY = src.clientY; - dest.ctrlKey = src.ctrlKey; - dest.shiftKey = src.shiftKey; - dest.altKey = src.altKey; - //dest.metaKey = src.metaKey; - dest.button = src.button; - //dest.buttons = src.buttons; - //dest.movementX = src.movementX; - //dest.movementY = src.movementY; - dest.targetX = src.targetX; - dest.targetY = src.targetY; - //dest.canvasX = src.canvasX; - //dest.canvasY = src.canvasY; - //dest.padding = src.padding; - } - - void ConvertFromPlatform( GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src) - { - ConvertFromPlatform(dest.mouse, eventType, src.mouse); - dest.deltaX = src.deltaX; - dest.deltaY = src.deltaY; - switch (src.deltaMode) - { - case DOM_DELTA_PIXEL: - dest.deltaMode = GUIADAPTER_DELTA_PIXEL; - break; - case DOM_DELTA_LINE: - dest.deltaMode = GUIADAPTER_DELTA_LINE; - break; - case DOM_DELTA_PAGE: - dest.deltaMode = GUIADAPTER_DELTA_PAGE; - break; - default: - ORTHANC_ASSERT(false, "Unknown deltaMode: " << src.deltaMode << - " in wheel event..."); - } - dest.deltaMode = src.deltaMode; - } - - void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src) - { - dest.sym[0] = src.key[0]; - dest.sym[1] = 0; - dest.ctrlKey = src.ctrlKey; - dest.shiftKey = src.shiftKey; - dest.altKey = src.altKey; - } - - template<typename GenericFunc> - struct FuncAdapterPayload - { - std::string canvasCssSelector; - void* userData; - GenericFunc callback; - }; - - template<typename GenericFunc, - typename GuiAdapterEvent, - typename EmscriptenEvent> - EM_BOOL OnEventAdapterFunc( - int eventType, const EmscriptenEvent* emEvent, void* userData) - { - // userData is OnMouseWheelFuncAdapterPayload - FuncAdapterPayload<GenericFunc>* payload = - reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); - // LOG(INFO) << "OnEventAdapterFunc"; - // LOG(INFO) << "------------------"; - // LOG(INFO) << "eventType: " << eventType << " wheelEvent: " << - // (int)wheelEvent << " userData: " << userData << - // " payload->userData: " << payload->userData; - - GuiAdapterEvent guiEvent; - ConvertFromPlatform(guiEvent, eventType, *emEvent); - bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData); - return static_cast<EM_BOOL>(ret); - } - - template<typename GenericFunc, - typename GuiAdapterEvent, - typename EmscriptenEvent> - EM_BOOL OnEventAdapterFunc2( - int /*eventType*/, const EmscriptenEvent* wheelEvent, void* userData) - { - // userData is OnMouseWheelFuncAdapterPayload - FuncAdapterPayload<GenericFunc>* payload = - reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); - - GuiAdapterEvent guiEvent; - ConvertFromPlatform(guiEvent, *wheelEvent); - bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData); - return static_cast<EM_BOOL>(ret); - } - - template<typename GenericFunc> - EM_BOOL OnEventAdapterFunc3( - double time, void* userData) - { - // userData is OnMouseWheelFuncAdapterPayload - FuncAdapterPayload<GenericFunc>* payload = - reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); - //std::unique_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload); - bool ret = (*(payload->callback))(time, payload->userData); - return static_cast<EM_BOOL>(ret); - } - - /* - - Explanation - =========== - - - in "older" Emscripten, where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR doesn't exist or is set to 0, - the following strings need to be used to register events: - - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs - to be "mycanvas" - - for the window (for key events), the string needs to be "#window" - - in newer Emscripten where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR==1 (or maybe is not there anymore, in the - future as of 2020-04-20) - - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs - to be "#mycanvas" (notice the "number sign", aka "hash", NOT AKA "sharp", as can be read on https://en.wikipedia.org/wiki/Number_sign) - - for the window (for key events), the string needs to be EMSCRIPTEN_EVENT_TARGET_WINDOW. I do not mean - "EMSCRIPTEN_EVENT_TARGET_WINDOW", but the #define EMSCRIPTEN_EVENT_TARGET_WINDOW ((const char*)2) that - can be found in emscripten/html5.h - - The code below converts the input canvasId (as in the old emscripten) to the emscripten-compliant one, with the - following compile condition : #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1 - - If the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR build parameter disappears, you might want to refactor this code - or continue to pass the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR compile macro (which is different from the CMake - variable) - - What we are doing below: - - in older Emscripten, the registration functions will receive "mycanvas" and "#window" and the callbacks will receive - the same std::string in their payload ("mycanvas" and "#window") - - - in newer Emscripten, the registration functions will receive "#mycanvas" and EMSCRIPTEN_EVENT_TARGET_WINDOW, but - the callbacks will receive "#mycanvas" and "#window" (since it is not possible to store the EMSCRIPTEN_EVENT_TARGET_WINDOW - magic value in an std::string, while we still want the callback to be able to change its behavior according to the - target element. - - */ - - void convertElementTarget(const char*& outCanvasCssSelectorSz, std::string& outCanvasCssSelector, const std::string& canvasId) - { - // only "#window" can start with a # - if (canvasId[0] == '#') - { - ORTHANC_ASSERT(canvasId == "#window"); - } -#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1 - if (canvasId == "#window") - { - // we store this in the payload so that the callback can - outCanvasCssSelector = "#window"; - outCanvasCssSelectorSz = EMSCRIPTEN_EVENT_TARGET_WINDOW; - } - else - { - outCanvasCssSelector = "#" + canvasId; - outCanvasCssSelectorSz = outCanvasCssSelector.c_str(); - } -#else - if (canvasId == "#window") - { - // we store this in the payload so that the callback can - outCanvasCssSelector = "#window"; - outCanvasCssSelectorSz = outCanvasCssSelector.c_str();; - } - else - { - outCanvasCssSelector = canvasId; - outCanvasCssSelectorSz = outCanvasCssSelector.c_str();; - } -#endif - } - - // resize: (const char* target, void* userData, EM_BOOL useCapture, em_ui_callback_func callback) - template< - typename GenericFunc, - typename GuiAdapterEvent, - typename EmscriptenEvent, - typename EmscriptenSetCallbackFunc> - static void SetCallback( - EmscriptenSetCallbackFunc emFunc, - std::string canvasId, void* userData, bool capture, GenericFunc func) - { - std::string canvasCssSelector; - const char* canvasCssSelectorSz = NULL; - convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId); - - // TODO: write RemoveCallback with an int id that gets returned from here - - // create userdata payload - std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>()); - payload->canvasCssSelector = canvasCssSelector; - payload->callback = func; - payload->userData = userData; - void* userDataRaw = reinterpret_cast<void*>(payload.release()); - - // call the registration function - (*emFunc)( - canvasCssSelectorSz, - userDataRaw, - static_cast<EM_BOOL>(capture), - &OnEventAdapterFunc<GenericFunc, GuiAdapterEvent, EmscriptenEvent>, - EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD); - } - - template< - typename GenericFunc, - typename GuiAdapterEvent, - typename EmscriptenEvent, - typename EmscriptenSetCallbackFunc> - static void SetCallback2( - EmscriptenSetCallbackFunc emFunc, - std::string canvasId, void* userData, bool capture, GenericFunc func) - { - std::string canvasCssSelector; - const char* canvasCssSelectorSz = NULL; - convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId); - - // TODO: write RemoveCallback with an int id that gets returned from here - - // create userdata payload - std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>()); - payload->canvasCssSelector = canvasCssSelector; - payload->callback = func; - payload->userData = userData; - void* userDataRaw = reinterpret_cast<void*>(payload.release()); - - // call the registration function - (*emFunc)( - canvasCssSelectorSz, - userDataRaw, - static_cast<EM_BOOL>(capture), - &OnEventAdapterFunc2<GenericFunc, GuiAdapterEvent, EmscriptenEvent>, - EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD); - } - - template< - typename GenericFunc, - typename EmscriptenSetCallbackFunc> - static void SetAnimationFrameCallback( - EmscriptenSetCallbackFunc emFunc, - void* userData, GenericFunc func) - { - std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload( - new FuncAdapterPayload<GenericFunc>() - ); - payload->canvasCssSelector = "UNDEFINED"; - payload->callback = func; - payload->userData = userData; - void* userDataRaw = reinterpret_cast<void*>(payload.release()); - (*emFunc)( - &OnEventAdapterFunc3<GenericFunc>, - userDataRaw); - } - - void GuiAdapter::SetWheelCallback( - std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func) - { - SetCallback<OnMouseWheelFunc, GuiAdapterWheelEvent, EmscriptenWheelEvent>( - &emscripten_set_wheel_callback_on_thread, - canvasId, - userData, - capture, - func); - } - - - void GuiAdapter::SetMouseDblClickCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( - &emscripten_set_dblclick_callback_on_thread, - canvasId, - userData, - capture, - func); - } - - - void GuiAdapter::SetMouseDownCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( - &emscripten_set_mousedown_callback_on_thread, - canvasId, - userData, - capture, - func); - } - - void GuiAdapter::SetMouseMoveCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - // LOG(INFO) << "SetMouseMoveCallback -- " << "supplied userData: " << - // userData; - - SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( - &emscripten_set_mousemove_callback_on_thread, - canvasId, - userData, - capture, - func); - } - - void GuiAdapter::SetMouseUpCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( - &emscripten_set_mouseup_callback_on_thread, - canvasId, - userData, - capture, - func); - } - - void GuiAdapter::SetKeyDownCallback( - std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) - { - SetCallback2<OnKeyDownFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>( - &emscripten_set_keydown_callback_on_thread, - canvasId, - userData, - capture, - func); - } - - void GuiAdapter::SetKeyUpCallback( - std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) - { - SetCallback2<OnKeyUpFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>( - &emscripten_set_keyup_callback_on_thread, - canvasId, - userData, - capture, - func); - } - -#if 0 - // useless under Wasm where canvas resize is handled automatically - void GuiAdapter::SetResizeCallback( - std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func) - { - SetCallback<OnWindowResizeFunc, GuiAdapterUiEvent, EmscriptenUiEvent>( - &emscripten_set_resize_callback_on_thread, - canvasId, - userData, - capture, - func); - } -#endif - - void GuiAdapter::RequestAnimationFrame( - OnAnimationFrameFunc func, void* userData) - { - SetAnimationFrameCallback<OnAnimationFrameFunc>( - &emscripten_request_animation_frame_loop, - userData, - func); - } - -#if 0 - void GuiAdapter::SetKeyDownCallback( - std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) - { - emscripten_set_keydown_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func); - } - void GuiAdapter::SetKeyUpCallback( - std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) - { - emscripten_set_keyup_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func); - } - - // handled from within WebAssemblyViewport - //void GuiAdapter::SetResizeCallback(std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func) - //{ - // emscripten_set_resize_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func); - //} - - void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData) - { - emscripten_request_animation_frame_loop(func, userData); - } -#endif - - -#else - - // SDL ONLY - void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source) - { - memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); - switch (source.type) - { - case SDL_MOUSEBUTTONDOWN: - if (source.button.clicks == 1) { - dest.type = GUIADAPTER_EVENT_MOUSEDOWN; - } else if (source.button.clicks == 2) { - dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK; - } else { - dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK; - LOG(WARNING) << "Multiple-click ignored."; - } - break; - case SDL_MOUSEMOTION: - dest.type = GUIADAPTER_EVENT_MOUSEMOVE; - break; - case SDL_MOUSEBUTTONUP: - dest.type = GUIADAPTER_EVENT_MOUSEUP; - break; - case SDL_MOUSEWHEEL: - dest.type = GUIADAPTER_EVENT_WHEEL; - break; - default: - LOG(ERROR) << "SDL event: " << source.type << " is not supported"; - ORTHANC_ASSERT(false, "Not supported"); - } - //dest.timestamp = src.timestamp; - //dest.screenX = src.screenX; - //dest.screenY = src.screenY; - //dest.clientX = src.clientX; - //dest.clientY = src.clientY; - dest.ctrlKey = ctrlPressed; - dest.shiftKey = shiftPressed; - dest.altKey = altPressed; - //dest.metaKey = src.metaKey; - switch (source.button.button) - { - case SDL_BUTTON_MIDDLE: - dest.button =GUIADAPTER_MOUSEBUTTON_MIDDLE; - break; - - case SDL_BUTTON_RIGHT: - dest.button = GUIADAPTER_MOUSEBUTTON_RIGHT; - break; - - case SDL_BUTTON_LEFT: - dest.button = GUIADAPTER_MOUSEBUTTON_LEFT; - break; - - default: - break; - } - //dest.buttons = src.buttons; - //dest.movementX = src.movementX; - //dest.movementY = src.movementY; - dest.targetX = source.button.x; - dest.targetY = source.button.y; - //dest.canvasX = src.canvasX; - //dest.canvasY = src.canvasY; - //dest.padding = src.padding; - } - - void ConvertFromPlatform( - GuiAdapterWheelEvent& dest, - bool ctrlPressed, bool shiftPressed, bool altPressed, - const SDL_Event& source) - { - ConvertFromPlatform(dest.mouse, ctrlPressed, shiftPressed, altPressed, source); - dest.deltaX = source.wheel.x; - dest.deltaY = source.wheel.y; - } - - void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& src) - { - memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); - switch (src.type) - { - case SDL_KEYDOWN: - dest.type = GUIADAPTER_EVENT_KEYDOWN; - break; - case SDL_KEYUP: - dest.type = GUIADAPTER_EVENT_KEYUP; - break; - default: - LOG(ERROR) << "SDL event: " << src.type << " is not supported"; - ORTHANC_ASSERT(false, "Not supported"); - } - dest.sym[0] = src.key.keysym.sym; - dest.sym[1] = 0; - - if (src.key.keysym.mod & KMOD_CTRL) - dest.ctrlKey = true; - else - dest.ctrlKey = false; - - if (src.key.keysym.mod & KMOD_SHIFT) - dest.shiftKey = true; - else - dest.shiftKey = false; - - if (src.key.keysym.mod & KMOD_ALT) - dest.altKey = true; - else - dest.altKey = false; - } - - // SDL ONLY - void GuiAdapter::SetSdlResizeCallback( - std::string canvasId, void* userData, bool capture, OnSdlWindowResizeFunc func) - { - resizeHandlers_.push_back(EventHandlerData<OnSdlWindowResizeFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetMouseDownCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - mouseDownHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetMouseDblClickCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - mouseDblCickHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetMouseMoveCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - mouseMoveHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetMouseUpCallback( - std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) - { - mouseUpHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetWheelCallback( - std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func) - { - mouseWheelHandlers_.push_back(EventHandlerData<OnMouseWheelFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetKeyDownCallback( - std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) - { - keyDownHandlers_.push_back(EventHandlerData<OnKeyDownFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetKeyUpCallback( - std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) - { - keyUpHandlers_.push_back(EventHandlerData<OnKeyUpFunc>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::SetGenericSdlEventCallback( - std::string canvasId, void* userData, bool capture, OnSdlEventCallback func) - { - sdlEventHandlers_.push_back(EventHandlerData<OnSdlEventCallback>(canvasId, func, userData)); - } - - // SDL ONLY - void GuiAdapter::OnAnimationFrame() - { - std::vector<size_t> disabledAnimationHandlers; - for (size_t i = 0; i < animationFrameHandlers_.size(); i++) - { - // TODO: fix time - bool goOn = (*(animationFrameHandlers_[i].first))(0, animationFrameHandlers_[i].second); - - // If the function returns false, we need to emulate what happens in Web - // and remove the function from the handlers... - if (!goOn) - disabledAnimationHandlers.push_back(i); - } - for (size_t i = 0; i < disabledAnimationHandlers.size(); i++) - { - ORTHANC_ASSERT(animationFrameHandlers_.begin() + disabledAnimationHandlers[i] < animationFrameHandlers_.end()); - animationFrameHandlers_.erase(animationFrameHandlers_.begin() + disabledAnimationHandlers[i]); - } - } - - // SDL ONLY - void GuiAdapter::OnResize(unsigned int width, unsigned int height) - { - for (size_t i = 0; i < resizeHandlers_.size(); i++) - { - (*(resizeHandlers_[i].func))( - resizeHandlers_[i].canvasName, NULL, width, height, resizeHandlers_[i].userData); - } - } - - - - void GuiAdapter::OnSdlGenericEvent(const SDL_Event& sdlEvent) - { - // Events related to a window are only sent to the related canvas - // User events are sent to everyone (we can't filter them here) - - /* - SDL_WindowEvent SDL_WINDOWEVENT - SDL_KeyboardEvent SDL_KEYDOWN - SDL_KEYUP - SDL_TextEditingEvent SDL_TEXTEDITING - SDL_TextInputEvent SDL_TEXTINPUT - SDL_MouseMotionEvent SDL_MOUSEMOTION - SDL_MouseButtonEvent SDL_MOUSEBUTTONDOWN - SDL_MOUSEBUTTONUP - SDL_MouseWheelEvent SDL_MOUSEWHEEL - SDL_UserEvent SDL_USEREVENT through ::SDL_LASTEVENT-1 - */ - - // if this string is left empty, it means the message will be sent to - // all widgets. - // otherwise, it contains the originating message window title - - std::string windowTitle; - uint32_t windowId = 0; - - if (sdlEvent.type == SDL_WINDOWEVENT) - windowId = sdlEvent.window.windowID; - else if (sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP) - windowId = sdlEvent.key.windowID; - else if (sdlEvent.type == SDL_TEXTEDITING) - windowId = sdlEvent.edit.windowID; - else if (sdlEvent.type == SDL_TEXTINPUT) - windowId = sdlEvent.text.windowID; - else if (sdlEvent.type == SDL_MOUSEMOTION) - windowId = sdlEvent.motion.windowID; - else if (sdlEvent.type == SDL_MOUSEBUTTONDOWN || sdlEvent.type == SDL_MOUSEBUTTONUP) - windowId = sdlEvent.button.windowID; - else if (sdlEvent.type == SDL_MOUSEWHEEL) - windowId = sdlEvent.wheel.windowID; - else if (sdlEvent.type >= SDL_USEREVENT && sdlEvent.type <= (SDL_LASTEVENT-1)) - windowId = sdlEvent.user.windowID; - - if (windowId != 0) - { - SDL_Window* sdlWindow = SDL_GetWindowFromID(windowId); - ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowId << "\" is not a valid SDL window ID!"); - const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); - ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowId << "\" has a NULL window title!"); - windowTitle = windowTitleSz; - ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowId << "\" has an empty window title!"); - } - - for (size_t i = 0; i < sdlEventHandlers_.size(); i++) - { - // normally, the handlers return a bool indicating whether they - // have handled the event or not, but we don't really care about this - std::string& canvasName = sdlEventHandlers_[i].canvasName; - - bool sendEvent = true; - - if (windowTitle != "" && (canvasName != windowTitle)) - sendEvent = false; - - if (sendEvent) - { - OnSdlEventCallback func = sdlEventHandlers_[i].func; - (*func)(canvasName, sdlEvent, sdlEventHandlers_[i].userData); - } - } - } - - // SDL ONLY - void GuiAdapter::OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event) - { - // the SDL window name IS the canvas name ("canvas" is used because this lib - // is designed for Wasm - SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); - ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); - - const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); - ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); - - std::string windowTitle(windowTitleSz); - ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); - - switch (event.mouse.type) - { - case GUIADAPTER_EVENT_WHEEL: - for (size_t i = 0; i < mouseWheelHandlers_.size(); i++) - { - if (mouseWheelHandlers_[i].canvasName == windowTitle) - (*(mouseWheelHandlers_[i].func))(windowTitle, &event, mouseWheelHandlers_[i].userData); - } - break; - default: - ORTHANC_ASSERT(false, "Wrong event.type: " << event.mouse.type << " in GuiAdapter::OnMouseWheelEvent(...)"); - break; - } - } - - - void GuiAdapter::OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event) - { - // only one-letter (ascii) keyboard events supported for now - ORTHANC_ASSERT(event.sym[0] != 0); - ORTHANC_ASSERT(event.sym[1] == 0); - - SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); - ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); - - const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); - ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); - - std::string windowTitle(windowTitleSz); - ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); - - switch (event.type) - { - case GUIADAPTER_EVENT_KEYDOWN: - for (size_t i = 0; i < keyDownHandlers_.size(); i++) - { - (*(keyDownHandlers_[i].func))(windowTitle, &event, keyDownHandlers_[i].userData); - } - break; - case GUIADAPTER_EVENT_KEYUP: - for (size_t i = 0; i < keyUpHandlers_.size(); i++) - { - (*(keyUpHandlers_[i].func))(windowTitle, &event, keyUpHandlers_[i].userData); - } - break; - default: - ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnKeyboardEvent(...)"); - break; - } - } - - // SDL ONLY - void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event) - { - if (windowID == 0) - { - LOG(WARNING) << "GuiAdapter::OnMouseEvent -- windowID == 0 and event won't be routed!"; - } - else - { - // the SDL window name IS the canvas name ("canvas" is used because this lib - // is designed for Wasm - SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); - - ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); - - const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); - ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); - - std::string windowTitle(windowTitleSz); - ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); - - switch (event.type) - { - case GUIADAPTER_EVENT_MOUSEDOWN: - for (size_t i = 0; i < mouseDownHandlers_.size(); i++) - { - if (mouseDownHandlers_[i].canvasName == windowTitle) - (*(mouseDownHandlers_[i].func))(windowTitle, &event, mouseDownHandlers_[i].userData); - } - break; - case GUIADAPTER_EVENT_MOUSEDBLCLICK: - for (size_t i = 0; i < mouseDblCickHandlers_.size(); i++) - { - if (mouseDblCickHandlers_[i].canvasName == windowTitle) - (*(mouseDblCickHandlers_[i].func))(windowTitle, &event, mouseDblCickHandlers_[i].userData); - } - break; - case GUIADAPTER_EVENT_MOUSEMOVE: - for (size_t i = 0; i < mouseMoveHandlers_.size(); i++) - { - if (mouseMoveHandlers_[i].canvasName == windowTitle) - (*(mouseMoveHandlers_[i].func))(windowTitle, &event, mouseMoveHandlers_[i].userData); - } - break; - case GUIADAPTER_EVENT_MOUSEUP: - for (size_t i = 0; i < mouseUpHandlers_.size(); i++) - { - if (mouseUpHandlers_[i].canvasName == windowTitle) - (*(mouseUpHandlers_[i].func))(windowTitle, &event, mouseUpHandlers_[i].userData); - } - break; - default: - ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)"); - break; - } - } - } - - - // extern void Debug_SetContextToBeKilled(std::string title); - // extern void Debug_SetContextToBeRestored(std::string title); - - // SDL ONLY - void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData) - { - animationFrameHandlers_.push_back(std::make_pair(func, userData)); - } - -# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__) /* OpenGL debug is not available on OS X */ - - // SDL ONLY - static void GLAPIENTRY - OpenGLMessageCallback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar * message, - const void* userParam) - { - if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) - { - fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", - (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), - type, severity, message); - } - } -# endif - -#if 0 - // TODO: remove this when generic sdl event handlers are implemented in - // the DoseView - // SDL ONLY - bool GuiAdapter::IsSdlViewPortRefreshEvent(const SDL_Event& event) const - { - SDL_Window* sdlWindow = SDL_GetWindowFromID(event.window.windowID); - - ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << event.window.windowID << "\" is not a valid SDL window ID!"); - - const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); - - // now we need to find the DoseView from from the canvas name! - // (and retrieve the SdlViewport) - boost::shared_ptr<IGuiAdapterWidget> foundWidget; - VisitWidgets([&foundWidget, windowTitleSz](auto widget) - { - if (widget->GetCanvasIdentifier() == std::string(windowTitleSz)) - foundWidget = widget; - }); - ORTHANC_ASSERT(foundWidget, "The window named: \"" << windowTitleSz << "\" was not found in the registered widgets!"); - return foundWidget->GetSdlViewport().IsRefreshEvent(event); - } -#endif - - // SDL ONLY - void GuiAdapter::Run(GuiAdapterRunFunc func, void* cookie) - { -#if 1 - // TODO: MAKE THIS DYNAMIC !!! See SdlOpenGLViewport vs Cairo in ViewportWrapper -# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__) - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(OpenGLMessageCallback, 0); -# endif -#endif - - // Uint32 SDL_GetWindowID(SDL_Window* window) - // SDL_Window* SDL_GetWindowFromID(Uint32 id) // may return NULL - - bool stop = false; - while (!stop) - { - { - // TODO: lock all viewports here! (use a scoped object) - if(func != NULL) - (*func)(cookie); - OnAnimationFrame(); // in SDL we must call it - } - - while (!stop) - { - std::vector<SDL_Event> sdlEvents; - std::map<Uint32,SDL_Event> userEventsMap; - - SDL_Event sdlEvent; - - // FIRST: collect all pending events - while (SDL_PollEvent(&sdlEvent) != 0) - { - if ( (sdlEvent.type >= SDL_USEREVENT) && - (sdlEvent.type < SDL_LASTEVENT) ) - { - // we don't want to have multiple events with the same event.type - userEventsMap[sdlEvent.type] = sdlEvent; - } - else - { - sdlEvents.push_back(sdlEvent); - } - } - - // SECOND: collect all user events - for (std::map<Uint32,SDL_Event>::const_iterator it = userEventsMap.begin(); it != userEventsMap.end(); ++it) - sdlEvents.push_back(it->second); - - // now process the events - for (std::vector<SDL_Event>::const_iterator it = sdlEvents.begin(); it != sdlEvents.end(); ++it) - { - const SDL_Event& sdlEvent = *it; - // TODO: lock all viewports here! (use a scoped object) - - if (sdlEvent.type == SDL_QUIT) - { - // TODO: call exit callbacks here - stop = true; - break; - } - else if ((sdlEvent.type == SDL_MOUSEMOTION) || - (sdlEvent.type == SDL_MOUSEBUTTONDOWN) || - (sdlEvent.type == SDL_MOUSEBUTTONUP)) - { - int scancodeCount = 0; - const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); - bool ctrlPressed(false); - bool shiftPressed(false); - bool altPressed(false); - - if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL]) - ctrlPressed = true; - if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL]) - ctrlPressed = true; - if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT]) - shiftPressed = true; - if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT]) - shiftPressed = true; - if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT]) - altPressed = true; - - GuiAdapterMouseEvent dest; - ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent); - OnMouseEvent(sdlEvent.window.windowID, dest); - #if 0 - // for reference, how to create trackers - if (tracker) - { - PointerEvent e; - e.AddPosition(compositor.GetPixelCenterCoordinates( - sdlEvent.button.x, sdlEvent.button.y)); - tracker->PointerMove(e); - } - #endif - } - else if (sdlEvent.type == SDL_MOUSEWHEEL) - { - - int scancodeCount = 0; - const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); - bool ctrlPressed(false); - bool shiftPressed(false); - bool altPressed(false); - - if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL]) - ctrlPressed = true; - if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL]) - ctrlPressed = true; - if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT]) - shiftPressed = true; - if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT]) - shiftPressed = true; - if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT]) - altPressed = true; - - GuiAdapterWheelEvent dest; - ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent); - OnMouseWheelEvent(sdlEvent.window.windowID, dest); - - //KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount); - - //int x, y; - //SDL_GetMouseState(&x, &y); - - //if (sdlEvent.wheel.y > 0) - //{ - // locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers); - //} - //else if (sdlEvent.wheel.y < 0) - //{ - // locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers); - //} - } - else if (sdlEvent.type == SDL_WINDOWEVENT && - (sdlEvent.window.event == SDL_WINDOWEVENT_RESIZED || - sdlEvent.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)) - { - #if 0 - tracker.reset(); - #endif - OnResize(sdlEvent.window.data1, sdlEvent.window.data2); - } - else if (sdlEvent.type == SDL_KEYDOWN && sdlEvent.key.repeat == 0 /* Ignore key bounce */) - { - switch (sdlEvent.key.keysym.sym) - { - case SDLK_f: - // window.GetWindow().ToggleMaximize(); //TODO: move to particular handler - break; - - // This commented out code was used to debug the context - // loss/restoring code (2019-08-10) - // case SDLK_k: - // { - // SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID); - // std::string windowTitle(SDL_GetWindowTitle(window)); - // Debug_SetContextToBeKilled(windowTitle); - // } - // break; - // case SDLK_l: - // { - // SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID); - // std::string windowTitle(SDL_GetWindowTitle(window)); - // Debug_SetContextToBeRestored(windowTitle); - // } - // break; - - case SDLK_q: - stop = true; - break; - - default: - GuiAdapterKeyboardEvent dest; - ConvertFromPlatform(dest, sdlEvent); - OnKeyboardEvent(sdlEvent.window.windowID, dest); - break; - } - } - - OnSdlGenericEvent(sdlEvent); - } - SDL_Delay(1); - } - } - } -#endif -} -
--- a/Deprecated/Applications/Generic/GuiAdapter.h Tue Jun 30 11:29:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ -#pragma once - -#include <string> - -#if ORTHANC_ENABLE_WASM != 1 -# ifdef __EMSCRIPTEN__ -# error __EMSCRIPTEN__ is defined and ORTHANC_ENABLE_WASM != 1 -# endif -#endif - -#if ORTHANC_ENABLE_WASM == 1 -# ifndef __EMSCRIPTEN__ -# error __EMSCRIPTEN__ is not defined and ORTHANC_ENABLE_WASM == 1 -# endif -#endif - -#if ORTHANC_ENABLE_WASM == 1 -# include <emscripten/html5.h> -#else -# if ORTHANC_ENABLE_SDL == 1 -# include <SDL.h> -# endif -#endif - -#include "../../../Framework/StoneException.h" - -#if ORTHANC_ENABLE_THREADS == 1 -# include "../../../Framework/Deprecated/Messages/LockingEmitter.h" -#endif - -#include <vector> -#include <boost/shared_ptr.hpp> -#include <boost/weak_ptr.hpp> - -namespace OrthancStone -{ -#if ORTHANC_ENABLE_SDL == 1 - class SdlViewport; -#endif - -#if 0 - - /** - This interface is used to store the widgets that are controlled by the - GuiAdapter and receive event callbacks. - The callbacks may possibly be downcast (using dynamic_cast, for safety) \ - to the actual widget type - */ - class IGuiAdapterWidget - { - public: - virtual ~IGuiAdapterWidget() {} - -#if #if ORTHANC_ENABLE_SDL == 1 - /** - Returns the SdlViewport that this widget contains. If the underlying - viewport type is *not* SDL, then an error is returned. - */ - virtual SdlViewport& GetSdlViewport() = 0; -#endif - }; - -#endif - - enum GuiAdapterMouseButtonType - { - GUIADAPTER_MOUSEBUTTON_LEFT = 0, - GUIADAPTER_MOUSEBUTTON_MIDDLE = 1, - GUIADAPTER_MOUSEBUTTON_RIGHT = 2 - }; - - - enum GuiAdapterHidEventType - { - GUIADAPTER_EVENT_MOUSEDOWN = 1973, - GUIADAPTER_EVENT_MOUSEMOVE = 1974, - GUIADAPTER_EVENT_MOUSEDBLCLICK = 1975, - GUIADAPTER_EVENT_MOUSEUP = 1976, - GUIADAPTER_EVENT_WHEEL = 1977, - GUIADAPTER_EVENT_KEYDOWN = 1978, - GUIADAPTER_EVENT_KEYUP = 1979, - }; - - const unsigned int GUIADAPTER_DELTA_PIXEL = 2973; - const unsigned int GUIADAPTER_DELTA_LINE = 2974; - const unsigned int GUIADAPTER_DELTA_PAGE = 2975; - - struct GuiAdapterUiEvent; - struct GuiAdapterMouseEvent; - struct GuiAdapterWheelEvent; - struct GuiAdapterKeyboardEvent; - -#if 1 - typedef bool (*OnMouseEventFunc) (std::string canvasId, const GuiAdapterMouseEvent* mouseEvent, void* userData); - typedef bool (*OnMouseWheelFunc) (std::string canvasId, const GuiAdapterWheelEvent* wheelEvent, void* userData); - typedef bool (*OnKeyDownFunc) (std::string canvasId, const GuiAdapterKeyboardEvent* keyEvent, void* userData); - typedef bool (*OnKeyUpFunc) (std::string canvasId, const GuiAdapterKeyboardEvent* keyEvent, void* userData); - typedef bool (*OnAnimationFrameFunc)(double time, void* userData); - -#if ORTHANC_ENABLE_SDL == 1 - typedef bool (*OnSdlEventCallback) (std::string canvasId, const SDL_Event& sdlEvent, void* userData); - - typedef bool (*OnSdlWindowResizeFunc)(std::string canvasId, - const GuiAdapterUiEvent* uiEvent, - unsigned int width, - unsigned int height, - void* userData); - - -#endif - -#else - -#if ORTHANC_ENABLE_WASM == 1 - typedef EM_BOOL (*OnMouseEventFunc)(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); - typedef EM_BOOL (*OnMouseWheelFunc)(int eventType, const EmscriptenWheelEvent* wheelEvent, void* userData); - typedef EM_BOOL (*OnKeyDownFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData); - typedef EM_BOOL (*OnKeyUpFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData); - - typedef EM_BOOL (*OnAnimationFrameFunc)(double time, void* userData); - typedef EM_BOOL (*OnWindowResizeFunc)(int eventType, const EmscriptenUiEvent* uiEvent, void* userData); -#else - typedef bool (*OnMouseEventFunc)(int eventType, const SDL_Event* mouseEvent, void* userData); - typedef bool (*OnMouseWheelFunc)(int eventType, const SDL_Event* wheelEvent, void* userData); - typedef bool (*OnKeyDownFunc) (int eventType, const SDL_Event* keyEvent, void* userData); - typedef bool (*OnKeyUpFunc) (int eventType, const SDL_Event* keyEvent, void* userData); - - typedef bool (*OnAnimationFrameFunc)(double time, void* userData); - typedef bool (*OnWindowResizeFunc)(int eventType, const GuiAdapterUiEvent* uiEvent, void* userData); -#endif - -#endif - struct GuiAdapterMouseEvent - { - GuiAdapterHidEventType type; - //double timestamp; - //long screenX; - //long screenY; - //long clientX; - //long clientY; - bool ctrlKey; - bool shiftKey; - bool altKey; - //bool metaKey; - unsigned short button; - //unsigned short buttons; - //long movementX; - //long movementY; - long targetX; - long targetY; - // 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) - //long canvasX; - //long canvasY; - //long padding; - - public: - GuiAdapterMouseEvent() - : ctrlKey(false), - shiftKey(false), - altKey(false) - { - } - }; - - struct GuiAdapterWheelEvent { - GuiAdapterMouseEvent mouse; - double deltaX; - double deltaY; - unsigned long deltaMode; - }; - - // we don't use any data now - struct GuiAdapterUiEvent {}; - - // EmscriptenKeyboardEvent - struct GuiAdapterKeyboardEvent - { - GuiAdapterHidEventType type; - char sym[32]; - bool ctrlKey; - bool shiftKey; - bool altKey; - }; - - std::ostream& operator<<(std::ostream& os, const GuiAdapterKeyboardEvent& event); - std::ostream& operator<<(std::ostream& os, const GuiAdapterMouseEvent& event); - - /* - Mousedown event trigger when either the left or right (or middle) mouse is pressed - on the object; - - Mouseup event trigger when either the left or right (or middle) mouse is released - above the object after triggered mousedown event and held. - - Click event trigger when the only left mouse button is pressed and released on the - same object, requires the Mousedown and Mouseup event happened before Click event. - - The normal expect trigger order: onMousedown >> onMouseup >> onClick - - Testing in Chrome v58, the time between onMouseup and onClick events are around - 7ms to 15ms - - FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/ - */ -#if ORTHANC_ENABLE_WASM == 1 - void ConvertFromPlatform(GuiAdapterUiEvent& dest, int eventType, const EmscriptenUiEvent& src); - - void ConvertFromPlatform(GuiAdapterMouseEvent& dest, int eventType, const EmscriptenMouseEvent& src); - - void ConvertFromPlatform(GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src); - - void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src); -#else - -# if ORTHANC_ENABLE_SDL == 1 - void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source); - - void ConvertFromPlatform(GuiAdapterWheelEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source); - - void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& source); - -# endif - -#endif - - typedef void (*GuiAdapterRunFunc)(void*); - - class GuiAdapter - { - public: - GuiAdapter() - { - ORTHANC_ASSERT(s_instanceCount == 0); - s_instanceCount = 1; - } - - ~GuiAdapter() - { - s_instanceCount -= 1; - } - - /** - emscripten_set_resize_callback("EMSCRIPTEN_EVENT_TARGET_WINDOW", NULL, false, OnWindowResize); - - emscripten_set_wheel_callback("#mycanvas1", widget1_.get(), false, OnXXXMouseWheel); - emscripten_set_wheel_callback("#mycanvas2", widget2_.get(), false, OnXXXMouseWheel); - emscripten_set_wheel_callback("#mycanvas3", widget3_.get(), false, OnXXXMouseWheel); - - emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyDown); ---> NO! - emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyUp); - - emscripten_request_animation_frame_loop(OnAnimationFrame, NULL); - - SDL: - see https://wiki.libsdl.org/SDL_CaptureMouse - - */ - - void SetMouseDownCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); - void SetMouseDblClickCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); - void SetMouseMoveCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); - void SetMouseUpCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); - void SetWheelCallback (std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func); - void SetKeyDownCallback (std::string canvasId, void* userData, bool capture, OnKeyDownFunc func); - void SetKeyUpCallback (std::string canvasId, void* userData, bool capture, OnKeyUpFunc func); - -#if ORTHANC_ENABLE_SDL == 1 - - void SetGenericSdlEventCallback (std::string canvasId, void* userData, bool capture, OnSdlEventCallback func); - - typedef bool (*OnSdlEventCallback) (std::string canvasId, const SDL_Event& sdlEvent, void* userData); - - // if you pass "#window", then any Window resize will trigger the callback - // (this special string is converted to EMSCRIPTEN_EVENT_TARGET_WINDOW in DOM, when DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1) - void SetSdlResizeCallback(std::string canvasId, - void* userData, - bool capture, - OnSdlWindowResizeFunc func); -#endif - - void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData); - - // TODO: implement and call to remove canvases [in SDL, although code should be generic] - void SetOnExitCallback(); - - /** - Under SDL, this function does NOT return until all windows have been closed. - Under wasm, it returns without doing anything, since the event loop is managed - by the browser. - */ - void Run(GuiAdapterRunFunc func = NULL, void* cookie = NULL); - - private: - -#if ORTHANC_ENABLE_SDL == 1 - /** - Gives observers a chance to react based on generic event handlers. This - is used, for instance, when the viewport lock interface is invalidated. - */ - void OnSdlGenericEvent(const SDL_Event& sdlEvent); -#endif - - /** - In SDL, this executes all the registered headers - */ - void OnAnimationFrame(); - - //void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData); - std::vector<std::pair<OnAnimationFrameFunc, void*> > - animationFrameHandlers_; - - void OnResize(unsigned int width, unsigned int height); - -#if ORTHANC_ENABLE_SDL == 1 - template<typename Func> - struct EventHandlerData - { - EventHandlerData(std::string canvasName, Func func, void* userData) - : canvasName(canvasName) - , func(func) - , userData(userData) - { - } - - std::string canvasName; - Func func; - void* userData; - }; - std::vector<EventHandlerData<OnSdlWindowResizeFunc> > resizeHandlers_; - std::vector<EventHandlerData<OnMouseEventFunc > > mouseDownHandlers_; - std::vector<EventHandlerData<OnMouseEventFunc > > mouseDblCickHandlers_; - std::vector<EventHandlerData<OnMouseEventFunc > > mouseMoveHandlers_; - std::vector<EventHandlerData<OnMouseEventFunc > > mouseUpHandlers_; - std::vector<EventHandlerData<OnMouseWheelFunc > > mouseWheelHandlers_; - std::vector<EventHandlerData<OnKeyDownFunc > > keyDownHandlers_; - std::vector<EventHandlerData<OnKeyUpFunc > > keyUpHandlers_; - std::vector<EventHandlerData<OnSdlEventCallback > > sdlEventHandlers_; - - /** - This executes all the registered headers if needed (in wasm, the browser - deals with this) - */ - void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event); - - void OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event); - - /** - Same remark as OnMouseEvent - */ - void OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event); - -#endif - - /** - This executes all the registered headers if needed (in wasm, the browser - deals with this) - */ - void ViewportsUpdateSize(); - - static int s_instanceCount; - }; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/GuiAdapter.cpp Tue Jun 30 11:37:34 2020 +0200 @@ -0,0 +1,1139 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "GuiAdapter.h" + +#if ORTHANC_ENABLE_OPENGL == 1 +# include "../OpenGL/OpenGLIncludes.h" +#endif + +#if ORTHANC_ENABLE_SDL == 1 +# include <SDL_video.h> +# include <SDL_render.h> +# include <SDL.h> +#endif + +#include <Compatibility.h> + +namespace OrthancStone +{ + std::ostream& operator<<( + std::ostream& os, const GuiAdapterKeyboardEvent& event) + { + os << "sym: " << event.sym << " (" << (int)(event.sym[0]) << ") ctrl: " << event.ctrlKey << ", " << + "shift: " << event.shiftKey << ", " << + "alt: " << event.altKey; + return os; + } + + std::ostream& operator<<( + std::ostream& os, const GuiAdapterMouseEvent& event) + { + os << "targetX: " << event.targetX << " targetY: " << event.targetY << " button: " << event.button + << "ctrlKey: " << event.ctrlKey << "shiftKey: " << event.shiftKey << "altKey: " << event.altKey; + + return os; + } + + int GuiAdapter::s_instanceCount = 0; + +#if ORTHANC_ENABLE_WASM == 1 + void GuiAdapter::Run(GuiAdapterRunFunc /*func*/, void* /*cookie*/) + { + } + + void ConvertFromPlatform( + GuiAdapterUiEvent& dest, + int eventType, + const EmscriptenUiEvent& src) + { + // no data for now + } + + void ConvertFromPlatform( + GuiAdapterMouseEvent& dest, + int eventType, + const EmscriptenMouseEvent& src) + { + memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); + switch (eventType) + { + case EMSCRIPTEN_EVENT_CLICK: + LOG(ERROR) << "Emscripten EMSCRIPTEN_EVENT_CLICK is not supported"; + ORTHANC_ASSERT(false, "Not supported"); + break; + case EMSCRIPTEN_EVENT_MOUSEDOWN: + dest.type = GUIADAPTER_EVENT_MOUSEDOWN; + break; + case EMSCRIPTEN_EVENT_DBLCLICK: + dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK; + break; + case EMSCRIPTEN_EVENT_MOUSEMOVE: + dest.type = GUIADAPTER_EVENT_MOUSEMOVE; + break; + case EMSCRIPTEN_EVENT_MOUSEUP: + dest.type = GUIADAPTER_EVENT_MOUSEUP; + break; + case EMSCRIPTEN_EVENT_WHEEL: + dest.type = GUIADAPTER_EVENT_WHEEL; + break; + + default: + LOG(ERROR) << "Emscripten event: " << eventType << " is not supported"; + ORTHANC_ASSERT(false, "Not supported"); + } + //dest.timestamp = src.timestamp; + //dest.screenX = src.screenX; + //dest.screenY = src.screenY; + //dest.clientX = src.clientX; + //dest.clientY = src.clientY; + dest.ctrlKey = src.ctrlKey; + dest.shiftKey = src.shiftKey; + dest.altKey = src.altKey; + //dest.metaKey = src.metaKey; + dest.button = src.button; + //dest.buttons = src.buttons; + //dest.movementX = src.movementX; + //dest.movementY = src.movementY; + dest.targetX = src.targetX; + dest.targetY = src.targetY; + //dest.canvasX = src.canvasX; + //dest.canvasY = src.canvasY; + //dest.padding = src.padding; + } + + void ConvertFromPlatform( GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src) + { + ConvertFromPlatform(dest.mouse, eventType, src.mouse); + dest.deltaX = src.deltaX; + dest.deltaY = src.deltaY; + switch (src.deltaMode) + { + case DOM_DELTA_PIXEL: + dest.deltaMode = GUIADAPTER_DELTA_PIXEL; + break; + case DOM_DELTA_LINE: + dest.deltaMode = GUIADAPTER_DELTA_LINE; + break; + case DOM_DELTA_PAGE: + dest.deltaMode = GUIADAPTER_DELTA_PAGE; + break; + default: + ORTHANC_ASSERT(false, "Unknown deltaMode: " << src.deltaMode << + " in wheel event..."); + } + dest.deltaMode = src.deltaMode; + } + + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src) + { + dest.sym[0] = src.key[0]; + dest.sym[1] = 0; + dest.ctrlKey = src.ctrlKey; + dest.shiftKey = src.shiftKey; + dest.altKey = src.altKey; + } + + template<typename GenericFunc> + struct FuncAdapterPayload + { + std::string canvasCssSelector; + void* userData; + GenericFunc callback; + }; + + template<typename GenericFunc, + typename GuiAdapterEvent, + typename EmscriptenEvent> + EM_BOOL OnEventAdapterFunc( + int eventType, const EmscriptenEvent* emEvent, void* userData) + { + // userData is OnMouseWheelFuncAdapterPayload + FuncAdapterPayload<GenericFunc>* payload = + reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); + // LOG(INFO) << "OnEventAdapterFunc"; + // LOG(INFO) << "------------------"; + // LOG(INFO) << "eventType: " << eventType << " wheelEvent: " << + // (int)wheelEvent << " userData: " << userData << + // " payload->userData: " << payload->userData; + + GuiAdapterEvent guiEvent; + ConvertFromPlatform(guiEvent, eventType, *emEvent); + bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData); + return static_cast<EM_BOOL>(ret); + } + + template<typename GenericFunc, + typename GuiAdapterEvent, + typename EmscriptenEvent> + EM_BOOL OnEventAdapterFunc2( + int /*eventType*/, const EmscriptenEvent* wheelEvent, void* userData) + { + // userData is OnMouseWheelFuncAdapterPayload + FuncAdapterPayload<GenericFunc>* payload = + reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); + + GuiAdapterEvent guiEvent; + ConvertFromPlatform(guiEvent, *wheelEvent); + bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData); + return static_cast<EM_BOOL>(ret); + } + + template<typename GenericFunc> + EM_BOOL OnEventAdapterFunc3( + double time, void* userData) + { + // userData is OnMouseWheelFuncAdapterPayload + FuncAdapterPayload<GenericFunc>* payload = + reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData); + //std::unique_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload); + bool ret = (*(payload->callback))(time, payload->userData); + return static_cast<EM_BOOL>(ret); + } + + /* + + Explanation + =========== + + - in "older" Emscripten, where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR doesn't exist or is set to 0, + the following strings need to be used to register events: + - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs + to be "mycanvas" + - for the window (for key events), the string needs to be "#window" + - in newer Emscripten where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR==1 (or maybe is not there anymore, in the + future as of 2020-04-20) + - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs + to be "#mycanvas" (notice the "number sign", aka "hash", NOT AKA "sharp", as can be read on https://en.wikipedia.org/wiki/Number_sign) + - for the window (for key events), the string needs to be EMSCRIPTEN_EVENT_TARGET_WINDOW. I do not mean + "EMSCRIPTEN_EVENT_TARGET_WINDOW", but the #define EMSCRIPTEN_EVENT_TARGET_WINDOW ((const char*)2) that + can be found in emscripten/html5.h + + The code below converts the input canvasId (as in the old emscripten) to the emscripten-compliant one, with the + following compile condition : #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1 + + If the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR build parameter disappears, you might want to refactor this code + or continue to pass the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR compile macro (which is different from the CMake + variable) + + What we are doing below: + - in older Emscripten, the registration functions will receive "mycanvas" and "#window" and the callbacks will receive + the same std::string in their payload ("mycanvas" and "#window") + + - in newer Emscripten, the registration functions will receive "#mycanvas" and EMSCRIPTEN_EVENT_TARGET_WINDOW, but + the callbacks will receive "#mycanvas" and "#window" (since it is not possible to store the EMSCRIPTEN_EVENT_TARGET_WINDOW + magic value in an std::string, while we still want the callback to be able to change its behavior according to the + target element. + + */ + + void convertElementTarget(const char*& outCanvasCssSelectorSz, std::string& outCanvasCssSelector, const std::string& canvasId) + { + // only "#window" can start with a # + if (canvasId[0] == '#') + { + ORTHANC_ASSERT(canvasId == "#window"); + } +#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1 + if (canvasId == "#window") + { + // we store this in the payload so that the callback can + outCanvasCssSelector = "#window"; + outCanvasCssSelectorSz = EMSCRIPTEN_EVENT_TARGET_WINDOW; + } + else + { + outCanvasCssSelector = "#" + canvasId; + outCanvasCssSelectorSz = outCanvasCssSelector.c_str(); + } +#else + if (canvasId == "#window") + { + // we store this in the payload so that the callback can + outCanvasCssSelector = "#window"; + outCanvasCssSelectorSz = outCanvasCssSelector.c_str();; + } + else + { + outCanvasCssSelector = canvasId; + outCanvasCssSelectorSz = outCanvasCssSelector.c_str();; + } +#endif + } + + // resize: (const char* target, void* userData, EM_BOOL useCapture, em_ui_callback_func callback) + template< + typename GenericFunc, + typename GuiAdapterEvent, + typename EmscriptenEvent, + typename EmscriptenSetCallbackFunc> + static void SetCallback( + EmscriptenSetCallbackFunc emFunc, + std::string canvasId, void* userData, bool capture, GenericFunc func) + { + std::string canvasCssSelector; + const char* canvasCssSelectorSz = NULL; + convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId); + + // TODO: write RemoveCallback with an int id that gets returned from here + + // create userdata payload + std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>()); + payload->canvasCssSelector = canvasCssSelector; + payload->callback = func; + payload->userData = userData; + void* userDataRaw = reinterpret_cast<void*>(payload.release()); + + // call the registration function + (*emFunc)( + canvasCssSelectorSz, + userDataRaw, + static_cast<EM_BOOL>(capture), + &OnEventAdapterFunc<GenericFunc, GuiAdapterEvent, EmscriptenEvent>, + EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD); + } + + template< + typename GenericFunc, + typename GuiAdapterEvent, + typename EmscriptenEvent, + typename EmscriptenSetCallbackFunc> + static void SetCallback2( + EmscriptenSetCallbackFunc emFunc, + std::string canvasId, void* userData, bool capture, GenericFunc func) + { + std::string canvasCssSelector; + const char* canvasCssSelectorSz = NULL; + convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId); + + // TODO: write RemoveCallback with an int id that gets returned from here + + // create userdata payload + std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>()); + payload->canvasCssSelector = canvasCssSelector; + payload->callback = func; + payload->userData = userData; + void* userDataRaw = reinterpret_cast<void*>(payload.release()); + + // call the registration function + (*emFunc)( + canvasCssSelectorSz, + userDataRaw, + static_cast<EM_BOOL>(capture), + &OnEventAdapterFunc2<GenericFunc, GuiAdapterEvent, EmscriptenEvent>, + EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD); + } + + template< + typename GenericFunc, + typename EmscriptenSetCallbackFunc> + static void SetAnimationFrameCallback( + EmscriptenSetCallbackFunc emFunc, + void* userData, GenericFunc func) + { + std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload( + new FuncAdapterPayload<GenericFunc>() + ); + payload->canvasCssSelector = "UNDEFINED"; + payload->callback = func; + payload->userData = userData; + void* userDataRaw = reinterpret_cast<void*>(payload.release()); + (*emFunc)( + &OnEventAdapterFunc3<GenericFunc>, + userDataRaw); + } + + void GuiAdapter::SetWheelCallback( + std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func) + { + SetCallback<OnMouseWheelFunc, GuiAdapterWheelEvent, EmscriptenWheelEvent>( + &emscripten_set_wheel_callback_on_thread, + canvasId, + userData, + capture, + func); + } + + + void GuiAdapter::SetMouseDblClickCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( + &emscripten_set_dblclick_callback_on_thread, + canvasId, + userData, + capture, + func); + } + + + void GuiAdapter::SetMouseDownCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( + &emscripten_set_mousedown_callback_on_thread, + canvasId, + userData, + capture, + func); + } + + void GuiAdapter::SetMouseMoveCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + // LOG(INFO) << "SetMouseMoveCallback -- " << "supplied userData: " << + // userData; + + SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( + &emscripten_set_mousemove_callback_on_thread, + canvasId, + userData, + capture, + func); + } + + void GuiAdapter::SetMouseUpCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>( + &emscripten_set_mouseup_callback_on_thread, + canvasId, + userData, + capture, + func); + } + + void GuiAdapter::SetKeyDownCallback( + std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) + { + SetCallback2<OnKeyDownFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>( + &emscripten_set_keydown_callback_on_thread, + canvasId, + userData, + capture, + func); + } + + void GuiAdapter::SetKeyUpCallback( + std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) + { + SetCallback2<OnKeyUpFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>( + &emscripten_set_keyup_callback_on_thread, + canvasId, + userData, + capture, + func); + } + +#if 0 + // useless under Wasm where canvas resize is handled automatically + void GuiAdapter::SetResizeCallback( + std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func) + { + SetCallback<OnWindowResizeFunc, GuiAdapterUiEvent, EmscriptenUiEvent>( + &emscripten_set_resize_callback_on_thread, + canvasId, + userData, + capture, + func); + } +#endif + + void GuiAdapter::RequestAnimationFrame( + OnAnimationFrameFunc func, void* userData) + { + SetAnimationFrameCallback<OnAnimationFrameFunc>( + &emscripten_request_animation_frame_loop, + userData, + func); + } + +#if 0 + void GuiAdapter::SetKeyDownCallback( + std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) + { + emscripten_set_keydown_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func); + } + void GuiAdapter::SetKeyUpCallback( + std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) + { + emscripten_set_keyup_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func); + } + + // handled from within WebAssemblyViewport + //void GuiAdapter::SetResizeCallback(std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func) + //{ + // emscripten_set_resize_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func); + //} + + void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData) + { + emscripten_request_animation_frame_loop(func, userData); + } +#endif + + +#else + + // SDL ONLY + void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source) + { + memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); + switch (source.type) + { + case SDL_MOUSEBUTTONDOWN: + if (source.button.clicks == 1) { + dest.type = GUIADAPTER_EVENT_MOUSEDOWN; + } else if (source.button.clicks == 2) { + dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK; + } else { + dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK; + LOG(WARNING) << "Multiple-click ignored."; + } + break; + case SDL_MOUSEMOTION: + dest.type = GUIADAPTER_EVENT_MOUSEMOVE; + break; + case SDL_MOUSEBUTTONUP: + dest.type = GUIADAPTER_EVENT_MOUSEUP; + break; + case SDL_MOUSEWHEEL: + dest.type = GUIADAPTER_EVENT_WHEEL; + break; + default: + LOG(ERROR) << "SDL event: " << source.type << " is not supported"; + ORTHANC_ASSERT(false, "Not supported"); + } + //dest.timestamp = src.timestamp; + //dest.screenX = src.screenX; + //dest.screenY = src.screenY; + //dest.clientX = src.clientX; + //dest.clientY = src.clientY; + dest.ctrlKey = ctrlPressed; + dest.shiftKey = shiftPressed; + dest.altKey = altPressed; + //dest.metaKey = src.metaKey; + switch (source.button.button) + { + case SDL_BUTTON_MIDDLE: + dest.button =GUIADAPTER_MOUSEBUTTON_MIDDLE; + break; + + case SDL_BUTTON_RIGHT: + dest.button = GUIADAPTER_MOUSEBUTTON_RIGHT; + break; + + case SDL_BUTTON_LEFT: + dest.button = GUIADAPTER_MOUSEBUTTON_LEFT; + break; + + default: + break; + } + //dest.buttons = src.buttons; + //dest.movementX = src.movementX; + //dest.movementY = src.movementY; + dest.targetX = source.button.x; + dest.targetY = source.button.y; + //dest.canvasX = src.canvasX; + //dest.canvasY = src.canvasY; + //dest.padding = src.padding; + } + + void ConvertFromPlatform( + GuiAdapterWheelEvent& dest, + bool ctrlPressed, bool shiftPressed, bool altPressed, + const SDL_Event& source) + { + ConvertFromPlatform(dest.mouse, ctrlPressed, shiftPressed, altPressed, source); + dest.deltaX = source.wheel.x; + dest.deltaY = source.wheel.y; + } + + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& src) + { + memset(&dest, 0, sizeof(GuiAdapterMouseEvent)); + switch (src.type) + { + case SDL_KEYDOWN: + dest.type = GUIADAPTER_EVENT_KEYDOWN; + break; + case SDL_KEYUP: + dest.type = GUIADAPTER_EVENT_KEYUP; + break; + default: + LOG(ERROR) << "SDL event: " << src.type << " is not supported"; + ORTHANC_ASSERT(false, "Not supported"); + } + dest.sym[0] = src.key.keysym.sym; + dest.sym[1] = 0; + + if (src.key.keysym.mod & KMOD_CTRL) + dest.ctrlKey = true; + else + dest.ctrlKey = false; + + if (src.key.keysym.mod & KMOD_SHIFT) + dest.shiftKey = true; + else + dest.shiftKey = false; + + if (src.key.keysym.mod & KMOD_ALT) + dest.altKey = true; + else + dest.altKey = false; + } + + // SDL ONLY + void GuiAdapter::SetSdlResizeCallback( + std::string canvasId, void* userData, bool capture, OnSdlWindowResizeFunc func) + { + resizeHandlers_.push_back(EventHandlerData<OnSdlWindowResizeFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetMouseDownCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + mouseDownHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetMouseDblClickCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + mouseDblCickHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetMouseMoveCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + mouseMoveHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetMouseUpCallback( + std::string canvasId, void* userData, bool capture, OnMouseEventFunc func) + { + mouseUpHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetWheelCallback( + std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func) + { + mouseWheelHandlers_.push_back(EventHandlerData<OnMouseWheelFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetKeyDownCallback( + std::string canvasId, void* userData, bool capture, OnKeyDownFunc func) + { + keyDownHandlers_.push_back(EventHandlerData<OnKeyDownFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetKeyUpCallback( + std::string canvasId, void* userData, bool capture, OnKeyUpFunc func) + { + keyUpHandlers_.push_back(EventHandlerData<OnKeyUpFunc>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::SetGenericSdlEventCallback( + std::string canvasId, void* userData, bool capture, OnSdlEventCallback func) + { + sdlEventHandlers_.push_back(EventHandlerData<OnSdlEventCallback>(canvasId, func, userData)); + } + + // SDL ONLY + void GuiAdapter::OnAnimationFrame() + { + std::vector<size_t> disabledAnimationHandlers; + for (size_t i = 0; i < animationFrameHandlers_.size(); i++) + { + // TODO: fix time + bool goOn = (*(animationFrameHandlers_[i].first))(0, animationFrameHandlers_[i].second); + + // If the function returns false, we need to emulate what happens in Web + // and remove the function from the handlers... + if (!goOn) + disabledAnimationHandlers.push_back(i); + } + for (size_t i = 0; i < disabledAnimationHandlers.size(); i++) + { + ORTHANC_ASSERT(animationFrameHandlers_.begin() + disabledAnimationHandlers[i] < animationFrameHandlers_.end()); + animationFrameHandlers_.erase(animationFrameHandlers_.begin() + disabledAnimationHandlers[i]); + } + } + + // SDL ONLY + void GuiAdapter::OnResize(unsigned int width, unsigned int height) + { + for (size_t i = 0; i < resizeHandlers_.size(); i++) + { + (*(resizeHandlers_[i].func))( + resizeHandlers_[i].canvasName, NULL, width, height, resizeHandlers_[i].userData); + } + } + + + + void GuiAdapter::OnSdlGenericEvent(const SDL_Event& sdlEvent) + { + // Events related to a window are only sent to the related canvas + // User events are sent to everyone (we can't filter them here) + + /* + SDL_WindowEvent SDL_WINDOWEVENT + SDL_KeyboardEvent SDL_KEYDOWN + SDL_KEYUP + SDL_TextEditingEvent SDL_TEXTEDITING + SDL_TextInputEvent SDL_TEXTINPUT + SDL_MouseMotionEvent SDL_MOUSEMOTION + SDL_MouseButtonEvent SDL_MOUSEBUTTONDOWN + SDL_MOUSEBUTTONUP + SDL_MouseWheelEvent SDL_MOUSEWHEEL + SDL_UserEvent SDL_USEREVENT through ::SDL_LASTEVENT-1 + */ + + // if this string is left empty, it means the message will be sent to + // all widgets. + // otherwise, it contains the originating message window title + + std::string windowTitle; + uint32_t windowId = 0; + + if (sdlEvent.type == SDL_WINDOWEVENT) + windowId = sdlEvent.window.windowID; + else if (sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP) + windowId = sdlEvent.key.windowID; + else if (sdlEvent.type == SDL_TEXTEDITING) + windowId = sdlEvent.edit.windowID; + else if (sdlEvent.type == SDL_TEXTINPUT) + windowId = sdlEvent.text.windowID; + else if (sdlEvent.type == SDL_MOUSEMOTION) + windowId = sdlEvent.motion.windowID; + else if (sdlEvent.type == SDL_MOUSEBUTTONDOWN || sdlEvent.type == SDL_MOUSEBUTTONUP) + windowId = sdlEvent.button.windowID; + else if (sdlEvent.type == SDL_MOUSEWHEEL) + windowId = sdlEvent.wheel.windowID; + else if (sdlEvent.type >= SDL_USEREVENT && sdlEvent.type <= (SDL_LASTEVENT-1)) + windowId = sdlEvent.user.windowID; + + if (windowId != 0) + { + SDL_Window* sdlWindow = SDL_GetWindowFromID(windowId); + ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowId << "\" is not a valid SDL window ID!"); + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); + ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowId << "\" has a NULL window title!"); + windowTitle = windowTitleSz; + ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowId << "\" has an empty window title!"); + } + + for (size_t i = 0; i < sdlEventHandlers_.size(); i++) + { + // normally, the handlers return a bool indicating whether they + // have handled the event or not, but we don't really care about this + std::string& canvasName = sdlEventHandlers_[i].canvasName; + + bool sendEvent = true; + + if (windowTitle != "" && (canvasName != windowTitle)) + sendEvent = false; + + if (sendEvent) + { + OnSdlEventCallback func = sdlEventHandlers_[i].func; + (*func)(canvasName, sdlEvent, sdlEventHandlers_[i].userData); + } + } + } + + // SDL ONLY + void GuiAdapter::OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event) + { + // the SDL window name IS the canvas name ("canvas" is used because this lib + // is designed for Wasm + SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); + ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); + + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); + ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); + + std::string windowTitle(windowTitleSz); + ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); + + switch (event.mouse.type) + { + case GUIADAPTER_EVENT_WHEEL: + for (size_t i = 0; i < mouseWheelHandlers_.size(); i++) + { + if (mouseWheelHandlers_[i].canvasName == windowTitle) + (*(mouseWheelHandlers_[i].func))(windowTitle, &event, mouseWheelHandlers_[i].userData); + } + break; + default: + ORTHANC_ASSERT(false, "Wrong event.type: " << event.mouse.type << " in GuiAdapter::OnMouseWheelEvent(...)"); + break; + } + } + + + void GuiAdapter::OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event) + { + // only one-letter (ascii) keyboard events supported for now + ORTHANC_ASSERT(event.sym[0] != 0); + ORTHANC_ASSERT(event.sym[1] == 0); + + SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); + ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); + + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); + ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); + + std::string windowTitle(windowTitleSz); + ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); + + switch (event.type) + { + case GUIADAPTER_EVENT_KEYDOWN: + for (size_t i = 0; i < keyDownHandlers_.size(); i++) + { + (*(keyDownHandlers_[i].func))(windowTitle, &event, keyDownHandlers_[i].userData); + } + break; + case GUIADAPTER_EVENT_KEYUP: + for (size_t i = 0; i < keyUpHandlers_.size(); i++) + { + (*(keyUpHandlers_[i].func))(windowTitle, &event, keyUpHandlers_[i].userData); + } + break; + default: + ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnKeyboardEvent(...)"); + break; + } + } + + // SDL ONLY + void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event) + { + if (windowID == 0) + { + LOG(WARNING) << "GuiAdapter::OnMouseEvent -- windowID == 0 and event won't be routed!"; + } + else + { + // the SDL window name IS the canvas name ("canvas" is used because this lib + // is designed for Wasm + SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID); + + ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!"); + + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); + ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!"); + + std::string windowTitle(windowTitleSz); + ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!"); + + switch (event.type) + { + case GUIADAPTER_EVENT_MOUSEDOWN: + for (size_t i = 0; i < mouseDownHandlers_.size(); i++) + { + if (mouseDownHandlers_[i].canvasName == windowTitle) + (*(mouseDownHandlers_[i].func))(windowTitle, &event, mouseDownHandlers_[i].userData); + } + break; + case GUIADAPTER_EVENT_MOUSEDBLCLICK: + for (size_t i = 0; i < mouseDblCickHandlers_.size(); i++) + { + if (mouseDblCickHandlers_[i].canvasName == windowTitle) + (*(mouseDblCickHandlers_[i].func))(windowTitle, &event, mouseDblCickHandlers_[i].userData); + } + break; + case GUIADAPTER_EVENT_MOUSEMOVE: + for (size_t i = 0; i < mouseMoveHandlers_.size(); i++) + { + if (mouseMoveHandlers_[i].canvasName == windowTitle) + (*(mouseMoveHandlers_[i].func))(windowTitle, &event, mouseMoveHandlers_[i].userData); + } + break; + case GUIADAPTER_EVENT_MOUSEUP: + for (size_t i = 0; i < mouseUpHandlers_.size(); i++) + { + if (mouseUpHandlers_[i].canvasName == windowTitle) + (*(mouseUpHandlers_[i].func))(windowTitle, &event, mouseUpHandlers_[i].userData); + } + break; + default: + ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)"); + break; + } + } + } + + + // extern void Debug_SetContextToBeKilled(std::string title); + // extern void Debug_SetContextToBeRestored(std::string title); + + // SDL ONLY + void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData) + { + animationFrameHandlers_.push_back(std::make_pair(func, userData)); + } + +# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__) /* OpenGL debug is not available on OS X */ + + // SDL ONLY + static void GLAPIENTRY + OpenGLMessageCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar * message, + const void* userParam) + { + if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) + { + fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", + (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), + type, severity, message); + } + } +# endif + +#if 0 + // TODO: remove this when generic sdl event handlers are implemented in + // the DoseView + // SDL ONLY + bool GuiAdapter::IsSdlViewPortRefreshEvent(const SDL_Event& event) const + { + SDL_Window* sdlWindow = SDL_GetWindowFromID(event.window.windowID); + + ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << event.window.windowID << "\" is not a valid SDL window ID!"); + + const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow); + + // now we need to find the DoseView from from the canvas name! + // (and retrieve the SdlViewport) + boost::shared_ptr<IGuiAdapterWidget> foundWidget; + VisitWidgets([&foundWidget, windowTitleSz](auto widget) + { + if (widget->GetCanvasIdentifier() == std::string(windowTitleSz)) + foundWidget = widget; + }); + ORTHANC_ASSERT(foundWidget, "The window named: \"" << windowTitleSz << "\" was not found in the registered widgets!"); + return foundWidget->GetSdlViewport().IsRefreshEvent(event); + } +#endif + + // SDL ONLY + void GuiAdapter::Run(GuiAdapterRunFunc func, void* cookie) + { +#if 1 + // TODO: MAKE THIS DYNAMIC !!! See SdlOpenGLViewport vs Cairo in ViewportWrapper +# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__) + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(OpenGLMessageCallback, 0); +# endif +#endif + + // Uint32 SDL_GetWindowID(SDL_Window* window) + // SDL_Window* SDL_GetWindowFromID(Uint32 id) // may return NULL + + bool stop = false; + while (!stop) + { + { + // TODO: lock all viewports here! (use a scoped object) + if(func != NULL) + (*func)(cookie); + OnAnimationFrame(); // in SDL we must call it + } + + while (!stop) + { + std::vector<SDL_Event> sdlEvents; + std::map<Uint32,SDL_Event> userEventsMap; + + SDL_Event sdlEvent; + + // FIRST: collect all pending events + while (SDL_PollEvent(&sdlEvent) != 0) + { + if ( (sdlEvent.type >= SDL_USEREVENT) && + (sdlEvent.type < SDL_LASTEVENT) ) + { + // we don't want to have multiple events with the same event.type + userEventsMap[sdlEvent.type] = sdlEvent; + } + else + { + sdlEvents.push_back(sdlEvent); + } + } + + // SECOND: collect all user events + for (std::map<Uint32,SDL_Event>::const_iterator it = userEventsMap.begin(); it != userEventsMap.end(); ++it) + sdlEvents.push_back(it->second); + + // now process the events + for (std::vector<SDL_Event>::const_iterator it = sdlEvents.begin(); it != sdlEvents.end(); ++it) + { + const SDL_Event& sdlEvent = *it; + // TODO: lock all viewports here! (use a scoped object) + + if (sdlEvent.type == SDL_QUIT) + { + // TODO: call exit callbacks here + stop = true; + break; + } + else if ((sdlEvent.type == SDL_MOUSEMOTION) || + (sdlEvent.type == SDL_MOUSEBUTTONDOWN) || + (sdlEvent.type == SDL_MOUSEBUTTONUP)) + { + int scancodeCount = 0; + const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); + bool ctrlPressed(false); + bool shiftPressed(false); + bool altPressed(false); + + if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL]) + ctrlPressed = true; + if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL]) + ctrlPressed = true; + if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT]) + shiftPressed = true; + if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT]) + shiftPressed = true; + if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT]) + altPressed = true; + + GuiAdapterMouseEvent dest; + ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent); + OnMouseEvent(sdlEvent.window.windowID, dest); + #if 0 + // for reference, how to create trackers + if (tracker) + { + PointerEvent e; + e.AddPosition(compositor.GetPixelCenterCoordinates( + sdlEvent.button.x, sdlEvent.button.y)); + tracker->PointerMove(e); + } + #endif + } + else if (sdlEvent.type == SDL_MOUSEWHEEL) + { + + int scancodeCount = 0; + const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); + bool ctrlPressed(false); + bool shiftPressed(false); + bool altPressed(false); + + if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL]) + ctrlPressed = true; + if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL]) + ctrlPressed = true; + if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT]) + shiftPressed = true; + if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT]) + shiftPressed = true; + if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT]) + altPressed = true; + + GuiAdapterWheelEvent dest; + ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent); + OnMouseWheelEvent(sdlEvent.window.windowID, dest); + + //KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount); + + //int x, y; + //SDL_GetMouseState(&x, &y); + + //if (sdlEvent.wheel.y > 0) + //{ + // locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers); + //} + //else if (sdlEvent.wheel.y < 0) + //{ + // locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers); + //} + } + else if (sdlEvent.type == SDL_WINDOWEVENT && + (sdlEvent.window.event == SDL_WINDOWEVENT_RESIZED || + sdlEvent.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)) + { + #if 0 + tracker.reset(); + #endif + OnResize(sdlEvent.window.data1, sdlEvent.window.data2); + } + else if (sdlEvent.type == SDL_KEYDOWN && sdlEvent.key.repeat == 0 /* Ignore key bounce */) + { + switch (sdlEvent.key.keysym.sym) + { + case SDLK_f: + // window.GetWindow().ToggleMaximize(); //TODO: move to particular handler + break; + + // This commented out code was used to debug the context + // loss/restoring code (2019-08-10) + // case SDLK_k: + // { + // SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID); + // std::string windowTitle(SDL_GetWindowTitle(window)); + // Debug_SetContextToBeKilled(windowTitle); + // } + // break; + // case SDLK_l: + // { + // SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID); + // std::string windowTitle(SDL_GetWindowTitle(window)); + // Debug_SetContextToBeRestored(windowTitle); + // } + // break; + + case SDLK_q: + stop = true; + break; + + default: + GuiAdapterKeyboardEvent dest; + ConvertFromPlatform(dest, sdlEvent); + OnKeyboardEvent(sdlEvent.window.windowID, dest); + break; + } + } + + OnSdlGenericEvent(sdlEvent); + } + SDL_Delay(1); + } + } + } +#endif +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/GuiAdapter.h Tue Jun 30 11:37:34 2020 +0200 @@ -0,0 +1,377 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ +#pragma once + +#include <string> + +#if ORTHANC_ENABLE_WASM != 1 +# ifdef __EMSCRIPTEN__ +# error __EMSCRIPTEN__ is defined and ORTHANC_ENABLE_WASM != 1 +# endif +#endif + +#if ORTHANC_ENABLE_WASM == 1 +# ifndef __EMSCRIPTEN__ +# error __EMSCRIPTEN__ is not defined and ORTHANC_ENABLE_WASM == 1 +# endif +#endif + +#if ORTHANC_ENABLE_WASM == 1 +# include <emscripten/html5.h> +#else +# if ORTHANC_ENABLE_SDL == 1 +# include <SDL.h> +# endif +#endif + +#include "../StoneException.h" + +#include <vector> +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + +namespace OrthancStone +{ +#if ORTHANC_ENABLE_SDL == 1 + class SdlViewport; +#endif + +#if 0 + + /** + This interface is used to store the widgets that are controlled by the + GuiAdapter and receive event callbacks. + The callbacks may possibly be downcast (using dynamic_cast, for safety) \ + to the actual widget type + */ + class IGuiAdapterWidget + { + public: + virtual ~IGuiAdapterWidget() {} + +#if #if ORTHANC_ENABLE_SDL == 1 + /** + Returns the SdlViewport that this widget contains. If the underlying + viewport type is *not* SDL, then an error is returned. + */ + virtual SdlViewport& GetSdlViewport() = 0; +#endif + }; + +#endif + + enum GuiAdapterMouseButtonType + { + GUIADAPTER_MOUSEBUTTON_LEFT = 0, + GUIADAPTER_MOUSEBUTTON_MIDDLE = 1, + GUIADAPTER_MOUSEBUTTON_RIGHT = 2 + }; + + + enum GuiAdapterHidEventType + { + GUIADAPTER_EVENT_MOUSEDOWN = 1973, + GUIADAPTER_EVENT_MOUSEMOVE = 1974, + GUIADAPTER_EVENT_MOUSEDBLCLICK = 1975, + GUIADAPTER_EVENT_MOUSEUP = 1976, + GUIADAPTER_EVENT_WHEEL = 1977, + GUIADAPTER_EVENT_KEYDOWN = 1978, + GUIADAPTER_EVENT_KEYUP = 1979, + }; + + const unsigned int GUIADAPTER_DELTA_PIXEL = 2973; + const unsigned int GUIADAPTER_DELTA_LINE = 2974; + const unsigned int GUIADAPTER_DELTA_PAGE = 2975; + + struct GuiAdapterUiEvent; + struct GuiAdapterMouseEvent; + struct GuiAdapterWheelEvent; + struct GuiAdapterKeyboardEvent; + +#if 1 + typedef bool (*OnMouseEventFunc) (std::string canvasId, const GuiAdapterMouseEvent* mouseEvent, void* userData); + typedef bool (*OnMouseWheelFunc) (std::string canvasId, const GuiAdapterWheelEvent* wheelEvent, void* userData); + typedef bool (*OnKeyDownFunc) (std::string canvasId, const GuiAdapterKeyboardEvent* keyEvent, void* userData); + typedef bool (*OnKeyUpFunc) (std::string canvasId, const GuiAdapterKeyboardEvent* keyEvent, void* userData); + typedef bool (*OnAnimationFrameFunc)(double time, void* userData); + +#if ORTHANC_ENABLE_SDL == 1 + typedef bool (*OnSdlEventCallback) (std::string canvasId, const SDL_Event& sdlEvent, void* userData); + + typedef bool (*OnSdlWindowResizeFunc)(std::string canvasId, + const GuiAdapterUiEvent* uiEvent, + unsigned int width, + unsigned int height, + void* userData); + + +#endif + +#else + +#if ORTHANC_ENABLE_WASM == 1 + typedef EM_BOOL (*OnMouseEventFunc)(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); + typedef EM_BOOL (*OnMouseWheelFunc)(int eventType, const EmscriptenWheelEvent* wheelEvent, void* userData); + typedef EM_BOOL (*OnKeyDownFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData); + typedef EM_BOOL (*OnKeyUpFunc) (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData); + + typedef EM_BOOL (*OnAnimationFrameFunc)(double time, void* userData); + typedef EM_BOOL (*OnWindowResizeFunc)(int eventType, const EmscriptenUiEvent* uiEvent, void* userData); +#else + typedef bool (*OnMouseEventFunc)(int eventType, const SDL_Event* mouseEvent, void* userData); + typedef bool (*OnMouseWheelFunc)(int eventType, const SDL_Event* wheelEvent, void* userData); + typedef bool (*OnKeyDownFunc) (int eventType, const SDL_Event* keyEvent, void* userData); + typedef bool (*OnKeyUpFunc) (int eventType, const SDL_Event* keyEvent, void* userData); + + typedef bool (*OnAnimationFrameFunc)(double time, void* userData); + typedef bool (*OnWindowResizeFunc)(int eventType, const GuiAdapterUiEvent* uiEvent, void* userData); +#endif + +#endif + struct GuiAdapterMouseEvent + { + GuiAdapterHidEventType type; + //double timestamp; + //long screenX; + //long screenY; + //long clientX; + //long clientY; + bool ctrlKey; + bool shiftKey; + bool altKey; + //bool metaKey; + unsigned short button; + //unsigned short buttons; + //long movementX; + //long movementY; + long targetX; + long targetY; + // 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) + //long canvasX; + //long canvasY; + //long padding; + + public: + GuiAdapterMouseEvent() + : ctrlKey(false), + shiftKey(false), + altKey(false) + { + } + }; + + struct GuiAdapterWheelEvent { + GuiAdapterMouseEvent mouse; + double deltaX; + double deltaY; + unsigned long deltaMode; + }; + + // we don't use any data now + struct GuiAdapterUiEvent {}; + + // EmscriptenKeyboardEvent + struct GuiAdapterKeyboardEvent + { + GuiAdapterHidEventType type; + char sym[32]; + bool ctrlKey; + bool shiftKey; + bool altKey; + }; + + std::ostream& operator<<(std::ostream& os, const GuiAdapterKeyboardEvent& event); + std::ostream& operator<<(std::ostream& os, const GuiAdapterMouseEvent& event); + + /* + Mousedown event trigger when either the left or right (or middle) mouse is pressed + on the object; + + Mouseup event trigger when either the left or right (or middle) mouse is released + above the object after triggered mousedown event and held. + + Click event trigger when the only left mouse button is pressed and released on the + same object, requires the Mousedown and Mouseup event happened before Click event. + + The normal expect trigger order: onMousedown >> onMouseup >> onClick + + Testing in Chrome v58, the time between onMouseup and onClick events are around + 7ms to 15ms + + FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/ + */ +#if ORTHANC_ENABLE_WASM == 1 + void ConvertFromPlatform(GuiAdapterUiEvent& dest, int eventType, const EmscriptenUiEvent& src); + + void ConvertFromPlatform(GuiAdapterMouseEvent& dest, int eventType, const EmscriptenMouseEvent& src); + + void ConvertFromPlatform(GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src); + + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src); +#else + +# if ORTHANC_ENABLE_SDL == 1 + void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source); + + void ConvertFromPlatform(GuiAdapterWheelEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source); + + void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& source); + +# endif + +#endif + + typedef void (*GuiAdapterRunFunc)(void*); + + class GuiAdapter + { + public: + GuiAdapter() + { + ORTHANC_ASSERT(s_instanceCount == 0); + s_instanceCount = 1; + } + + ~GuiAdapter() + { + s_instanceCount -= 1; + } + + /** + emscripten_set_resize_callback("EMSCRIPTEN_EVENT_TARGET_WINDOW", NULL, false, OnWindowResize); + + emscripten_set_wheel_callback("#mycanvas1", widget1_.get(), false, OnXXXMouseWheel); + emscripten_set_wheel_callback("#mycanvas2", widget2_.get(), false, OnXXXMouseWheel); + emscripten_set_wheel_callback("#mycanvas3", widget3_.get(), false, OnXXXMouseWheel); + + emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyDown); ---> NO! + emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyUp); + + emscripten_request_animation_frame_loop(OnAnimationFrame, NULL); + + SDL: + see https://wiki.libsdl.org/SDL_CaptureMouse + + */ + + void SetMouseDownCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); + void SetMouseDblClickCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); + void SetMouseMoveCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); + void SetMouseUpCallback (std::string canvasId, void* userData, bool capture, OnMouseEventFunc func); + void SetWheelCallback (std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func); + void SetKeyDownCallback (std::string canvasId, void* userData, bool capture, OnKeyDownFunc func); + void SetKeyUpCallback (std::string canvasId, void* userData, bool capture, OnKeyUpFunc func); + +#if ORTHANC_ENABLE_SDL == 1 + + void SetGenericSdlEventCallback (std::string canvasId, void* userData, bool capture, OnSdlEventCallback func); + + typedef bool (*OnSdlEventCallback) (std::string canvasId, const SDL_Event& sdlEvent, void* userData); + + // if you pass "#window", then any Window resize will trigger the callback + // (this special string is converted to EMSCRIPTEN_EVENT_TARGET_WINDOW in DOM, when DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1) + void SetSdlResizeCallback(std::string canvasId, + void* userData, + bool capture, + OnSdlWindowResizeFunc func); +#endif + + void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData); + + // TODO: implement and call to remove canvases [in SDL, although code should be generic] + void SetOnExitCallback(); + + /** + Under SDL, this function does NOT return until all windows have been closed. + Under wasm, it returns without doing anything, since the event loop is managed + by the browser. + */ + void Run(GuiAdapterRunFunc func = NULL, void* cookie = NULL); + + private: + +#if ORTHANC_ENABLE_SDL == 1 + /** + Gives observers a chance to react based on generic event handlers. This + is used, for instance, when the viewport lock interface is invalidated. + */ + void OnSdlGenericEvent(const SDL_Event& sdlEvent); +#endif + + /** + In SDL, this executes all the registered headers + */ + void OnAnimationFrame(); + + //void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData); + std::vector<std::pair<OnAnimationFrameFunc, void*> > + animationFrameHandlers_; + + void OnResize(unsigned int width, unsigned int height); + +#if ORTHANC_ENABLE_SDL == 1 + template<typename Func> + struct EventHandlerData + { + EventHandlerData(std::string canvasName, Func func, void* userData) + : canvasName(canvasName) + , func(func) + , userData(userData) + { + } + + std::string canvasName; + Func func; + void* userData; + }; + std::vector<EventHandlerData<OnSdlWindowResizeFunc> > resizeHandlers_; + std::vector<EventHandlerData<OnMouseEventFunc > > mouseDownHandlers_; + std::vector<EventHandlerData<OnMouseEventFunc > > mouseDblCickHandlers_; + std::vector<EventHandlerData<OnMouseEventFunc > > mouseMoveHandlers_; + std::vector<EventHandlerData<OnMouseEventFunc > > mouseUpHandlers_; + std::vector<EventHandlerData<OnMouseWheelFunc > > mouseWheelHandlers_; + std::vector<EventHandlerData<OnKeyDownFunc > > keyDownHandlers_; + std::vector<EventHandlerData<OnKeyUpFunc > > keyUpHandlers_; + std::vector<EventHandlerData<OnSdlEventCallback > > sdlEventHandlers_; + + /** + This executes all the registered headers if needed (in wasm, the browser + deals with this) + */ + void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event); + + void OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event); + + /** + Same remark as OnMouseEvent + */ + void OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event); + +#endif + + /** + This executes all the registered headers if needed (in wasm, the browser + deals with this) + */ + void ViewportsUpdateSize(); + + static int s_instanceCount; + }; +}
--- a/Resources/CMake/OrthancStoneConfiguration.cmake Tue Jun 30 11:29:41 2020 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Tue Jun 30 11:37:34 2020 +0200 @@ -265,8 +265,8 @@ if ((ENABLE_SDL OR ENABLE_WASM) AND ENABLE_GUIADAPTER) list(APPEND APPLICATIONS_SOURCES - ${ORTHANC_STONE_ROOT}/Deprecated/Applications/Generic/GuiAdapter.cpp - ${ORTHANC_STONE_ROOT}/Deprecated/Applications/Generic/GuiAdapter.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/GuiAdapter.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/GuiAdapter.h ) endif()