# HG changeset patch # User Benjamin Golinvaux # Date 1584353559 -3600 # Node ID f30905f5d24637525ca24102d6c091a1688eb887 # Parent 4f8c9065ee52eb2128d862896118988ede84eeb4 Added support for OnGenericSdlEvent to GuiAdapter. This makes it possible to piggyback app-specific logic to special events (here, to support the Viewport refresh events) diff -r 4f8c9065ee52 -r f30905f5d246 Applications/Generic/GuiAdapter.cpp --- a/Applications/Generic/GuiAdapter.cpp Mon Mar 09 14:56:04 2020 +0100 +++ b/Applications/Generic/GuiAdapter.cpp Mon Mar 16 11:12:39 2020 +0100 @@ -520,15 +520,12 @@ dest.altKey = false; } - -#if ORTHANC_ENABLE_WASM != 1 // SDL ONLY void GuiAdapter::SetSdlResizeCallback( std::string canvasId, void* userData, bool capture, OnSdlWindowResizeFunc func) { resizeHandlers_.push_back(EventHandlerData(canvasId, func, userData)); } -#endif // SDL ONLY void GuiAdapter::SetMouseDownCallback( @@ -580,6 +577,13 @@ } // SDL ONLY + void GuiAdapter::SetGenericSdlEventCallback( + std::string canvasId, void* userData, bool capture, OnSdlEventCallback func) + { + sdlEventHandlers_.push_back(EventHandlerData(canvasId, func, userData)); + } + + // SDL ONLY void GuiAdapter::OnAnimationFrame() { std::vector disabledAnimationHandlers; @@ -610,10 +614,82 @@ } } + + + 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) + { + auto 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); @@ -731,17 +807,6 @@ ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)"); break; } - - ////boost::shared_ptr GetWidgetFromWindowId(); - //boost::shared_ptr foundWidget; - //VisitWidgets([foundWidget, windowID](auto widget) - // { - // if (widget->GetSdlWindowID() == windowID) - // foundWidget = widget; - // }); - //ORTHANC_ASSERT(foundWidget, "WindowID " << windowID << " was not found in the registered widgets!"); - //if(foundWidget) - // foundWidget-> } } @@ -776,6 +841,31 @@ } # endif +#if 0 + // TODO: remove this when generic sdl event handlers are implemented in + // the VolumeSlicerWidget + // 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 VolumeSlicerWidget from from the canvas name! + // (and retrieve the SdlViewport) + boost::shared_ptr 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) { @@ -800,137 +890,164 @@ OnAnimationFrame(); // in SDL we must call it } - SDL_Event event; - - while (!stop && SDL_PollEvent(&event)) + while (!stop) { - // TODO: lock all viewports here! (use a scoped object) - - if (event.type == SDL_QUIT) - { - // TODO: call exit callbacks here - stop = true; - break; - } - else if ((event.type == SDL_MOUSEMOTION) || - (event.type == SDL_MOUSEBUTTONDOWN) || - (event.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, event); - OnMouseEvent(event.window.windowID, dest); -#if 0 - // for reference, how to create trackers - if (tracker) - { - PointerEvent e; - e.AddPosition(compositor.GetPixelCenterCoordinates( - event.button.x, event.button.y)); - tracker->PointerMove(e); - } -#endif - } - else if (event.type == SDL_MOUSEWHEEL) - { - - int scancodeCount = 0; - const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); - bool ctrlPressed(false); - bool shiftPressed(false); - bool altPressed(false); + std::vector sdlEvents; + std::map userEventsMap; + + SDL_Event sdlEvent; - 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, event); - OnMouseWheelEvent(event.window.windowID, dest); - - //KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount); - - //int x, y; - //SDL_GetMouseState(&x, &y); - - //if (event.wheel.y > 0) - //{ - // locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers); - //} - //else if (event.wheel.y < 0) - //{ - // locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers); - //} + // FIRST: collect all pending events + while (SDL_PollEvent(&sdlEvent) != 0) + { + if ( (sdlEvent.type >= SDL_USEREVENT) && + (sdlEvent.type <= SDL_USEREVENT) ) + { + // we don't want to have multiple events with the same event.type + userEventsMap[sdlEvent.type] = sdlEvent; + } + else + { + sdlEvents.push_back(sdlEvent); + } } - else if (event.type == SDL_WINDOWEVENT && - (event.window.event == SDL_WINDOWEVENT_RESIZED || - event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)) - { -#if 0 - tracker.reset(); -#endif - OnResize(event.window.data1, event.window.data2); - } - else if (event.type == SDL_KEYDOWN && event.key.repeat == 0 /* Ignore key bounce */) - { - switch (event.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(event.window.windowID); - // std::string windowTitle(SDL_GetWindowTitle(window)); - // Debug_SetContextToBeKilled(windowTitle); - // } - // break; - // case SDLK_l: - // { - // SDL_Window* window = SDL_GetWindowFromID(event.window.windowID); - // std::string windowTitle(SDL_GetWindowTitle(window)); - // Debug_SetContextToBeRestored(windowTitle); - // } - // break; + // SECOND: collect all user events + for (auto& it : userEventsMap) + sdlEvents.push_back(it.second); + + // now process the events + for(const SDL_Event& sdlEvent : sdlEvents) + { + // TODO: lock all viewports here! (use a scoped object) - case SDLK_q: + 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); - default: - GuiAdapterKeyboardEvent dest; - ConvertFromPlatform(dest, event); - OnKeyboardEvent(event.window.windowID, dest); - break; + 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); } - // HandleApplicationEvent(controller, compositor, event, tracker); } SDL_Delay(1); diff -r 4f8c9065ee52 -r f30905f5d246 Applications/Generic/GuiAdapter.h --- a/Applications/Generic/GuiAdapter.h Mon Mar 09 14:56:04 2020 +0100 +++ b/Applications/Generic/GuiAdapter.h Mon Mar 16 11:12:39 2020 +0100 @@ -53,6 +53,14 @@ namespace OrthancStone { +#if ORTHANC_ENABLE_WASM != 1 + class SdlViewport; +#endif + +#if 0 + + // events are now handled directly by the VolumeSlicerWidget... The + // GuiAdapter doesn't know about widgets anymore /** This interface is used to store the widgets that are controlled by the @@ -64,8 +72,17 @@ { public: virtual ~IGuiAdapterWidget() {} + +#if ORTHANC_ENABLE_WASM != 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 { @@ -96,12 +113,12 @@ 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 (*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); + typedef bool (*OnSdlEventCallback) (std::string canvasId, const SDL_Event& sdlEvent, void* userData); #if ORTHANC_ENABLE_WASM != 1 typedef bool (*OnSdlWindowResizeFunc)(std::string canvasId, @@ -109,6 +126,8 @@ unsigned int width, unsigned int height, void* userData); + + #endif #else @@ -253,14 +272,18 @@ */ - 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); - + 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); + void SetGenericSdlEventCallback (std::string canvasId, void* userData, bool capture, OnSdlEventCallback func); + + typedef bool (*OnSdlEventCallback) (std::string canvasId, const SDL_Event& sdlEvent, void* userData); + + #if ORTHANC_ENABLE_WASM != 1 // if you pass "#window", then any Window resize will trigger the callback void SetSdlResizeCallback(std::string canvasId, @@ -283,6 +306,13 @@ private: +#if ORTHANC_ENABLE_WASM != 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 @@ -318,6 +348,7 @@ std::vector > mouseWheelHandlers_; std::vector > keyDownHandlers_; std::vector > keyUpHandlers_; + std::vector > sdlEventHandlers_; /** This executes all the registered headers if needed (in wasm, the browser @@ -332,8 +363,6 @@ */ void OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event); - boost::shared_ptr GetWidgetFromWindowId(); - #endif /**