diff Applications/Generic/GuiAdapter.cpp @ 858:e3c56d4f863f

GuiAdapter : mouse event routing in SDL + split the undo stack from the ViewportController for multi-canvas apps + adapted the samples to this change
author Benjamin Golinvaux <bgo@osimis.io>
date Mon, 24 Jun 2019 10:31:04 +0200
parents bb88686acecc
children f0bf971a1e31 12b591d5d63c
line wrap: on
line diff
--- a/Applications/Generic/GuiAdapter.cpp	Wed Jun 19 14:12:28 2019 +0200
+++ b/Applications/Generic/GuiAdapter.cpp	Mon Jun 24 10:31:04 2019 +0200
@@ -41,6 +41,15 @@
     widgets_.push_back(widget);
   }
 
+  std::ostream& operator<<(
+    std::ostream& os, const GuiAdapterKeyboardEvent& event)
+  {
+    os << "ctrl: " << event.ctrlKey << ", " <<
+      "shift: " << event.shiftKey << ", " <<
+      "alt: " << event.altKey;
+    return os;
+  }
+
 #if ORTHANC_ENABLE_WASM == 1
   void GuiAdapter::Run()
   {
@@ -141,7 +150,8 @@
   template<typename GenericFunc>
   struct FuncAdapterPayload
   {
-    void*       userData;
+    std::string canvasId;
+    void* userData;
     GenericFunc callback;
   };
 
@@ -149,7 +159,7 @@
            typename GuiAdapterEvent,
            typename EmscriptenEvent>
   EM_BOOL OnEventAdapterFunc(
-    int eventType, const EmscriptenEvent* wheelEvent, void* userData)
+    int eventType, const EmscriptenEvent* emEvent, void* userData)
   {
 
     // userData is OnMouseWheelFuncAdapterPayload
@@ -162,8 +172,8 @@
     //   " payload->userData: " << payload->userData;
     
     GuiAdapterEvent guiEvent;
-    ConvertFromPlatform(guiEvent, eventType, *wheelEvent);
-    bool ret = (*(payload->callback))(&guiEvent, payload->userData);
+    ConvertFromPlatform(guiEvent, eventType, *emEvent);
+    bool ret = (*(payload->callback))(payload->canvasId, &guiEvent, payload->userData);
     return static_cast<EM_BOOL>(ret);
   }
 
@@ -179,7 +189,7 @@
     
     GuiAdapterEvent guiEvent;
     ConvertFromPlatform(guiEvent, *wheelEvent);
-    bool ret = (*(payload->callback))(&guiEvent, payload->userData);
+    bool ret = (*(payload->callback))(payload->canvasId, &guiEvent, payload->userData);
     return static_cast<EM_BOOL>(ret);
   }
 
@@ -210,6 +220,7 @@
     FuncAdapterPayload<GenericFunc>* payload = 
       new FuncAdapterPayload<GenericFunc>();
     std::auto_ptr<FuncAdapterPayload<GenericFunc> > payloadP(payload);
+    payload->canvasId = canvasId;
     payload->callback = func;
     payload->userData = userData;
     void* userDataRaw = reinterpret_cast<void*>(payload);
@@ -236,6 +247,7 @@
     std::auto_ptr<FuncAdapterPayload<GenericFunc> > payload(
       new FuncAdapterPayload<GenericFunc>()
     );
+    payload->canvasId = canvasId;
     payload->callback = func;
     payload->userData = userData;
     void* userDataRaw = reinterpret_cast<void*>(payload.release());
@@ -250,14 +262,15 @@
   template<
     typename GenericFunc,
     typename EmscriptenSetCallbackFunc>
-    static void SetCallback3(
+    static void SetAnimationFrameCallback(
       EmscriptenSetCallbackFunc emFunc,
       void* userData, GenericFunc func)
   {
-    // LOG(ERROR) << "SetCallback3 !!!!!! (RequestAnimationFrame)";
+    // LOG(ERROR) << "SetAnimationFrameCallback !!!!!! (RequestAnimationFrame)";
     std::auto_ptr<FuncAdapterPayload<GenericFunc> > payload(
       new FuncAdapterPayload<GenericFunc>()
     );
+    payload->canvasId = "UNDEFINED";
     payload->callback = func;
     payload->userData = userData;
     void* userDataRaw = reinterpret_cast<void*>(payload.release());
@@ -352,7 +365,7 @@
     // LOG(ERROR) << "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+";
     // LOG(ERROR) << "RequestAnimationFrame";
     // LOG(ERROR) << "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+";
-    SetCallback3<OnAnimationFrameFunc>(
+    SetAnimationFrameCallback<OnAnimationFrameFunc>(
       &emscripten_request_animation_frame_loop,
       userData,
       func);
@@ -384,6 +397,7 @@
 
 #else
 
+// SDL ONLY
 void ConvertFromPlatform(
   GuiAdapterMouseEvent& dest,
   bool ctrlPressed, bool shiftPressed, bool altPressed,
@@ -401,6 +415,9 @@
   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");
@@ -441,43 +458,67 @@
   //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;
+}
+
+
+
+  // SDL ONLY
   void GuiAdapter::SetResizeCallback(
     std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
   {
-    resizeHandlers_.push_back(std::make_pair(func, userData));
+    resizeHandlers_.push_back(EventHandlerData<OnWindowResizeFunc>(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::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));
+  }
 
- void GuiAdapter::SetWheelCallback(
+  // SDL ONLY
+  void GuiAdapter::SetWheelCallback(
    std::string canvasId, void* userData, bool capture, OnMouseWheelFunc  func)
- {
- }
+  {
+    mouseWheelHandlers_.push_back(EventHandlerData<OnMouseWheelFunc>(canvasId, func, userData));
+  }
 
- void GuiAdapter::SetKeyDownCallback(
+  // SDL ONLY
+  void GuiAdapter::SetKeyDownCallback(
    std::string canvasId, void* userData, bool capture, OnKeyDownFunc   func)
  {
  }
 
- void GuiAdapter::SetKeyUpCallback(
+  // SDL ONLY
+  void GuiAdapter::SetKeyUpCallback(
    std::string canvasId, void* userData, bool capture, OnKeyUpFunc    func)
  {
  }
 
 
+  // SDL ONLY
   void GuiAdapter::OnAnimationFrame()
   {
     for (size_t i = 0; i < animationFrameHandlers_.size(); i++)
@@ -487,20 +528,101 @@
     }
   }
 
+  // SDL ONLY
   void GuiAdapter::OnResize()
   {
     for (size_t i = 0; i < resizeHandlers_.size(); i++)
     {
-      // TODO: fix time 
-      (*(resizeHandlers_[i].first))(0, resizeHandlers_[i].second);
+      (*(resizeHandlers_[i].func))(
+        resizeHandlers_[i].canvasName, 0, resizeHandlers_[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;
     }
   }
-   
+
+  // SDL ONLY
   void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& 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.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_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;
+    }
+
+    ////boost::shared_ptr<IGuiAdapterWidget> GetWidgetFromWindowId();
+    //boost::shared_ptr<IGuiAdapterWidget> 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->
   }
 
-
+  // SDL ONLY
   void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
   {
     animationFrameHandlers_.push_back(std::make_pair(func, userData));
@@ -508,6 +630,7 @@
 
 # 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,
@@ -526,6 +649,7 @@
 }
 # endif
 
+  // SDL ONLY
   void GuiAdapter::Run()
   {
 # if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__)
@@ -591,6 +715,44 @@
           }
 #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);
+
+          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);
+          //}
+        }
         else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
         {
 #if 0