changeset 1463:182bf3106ee2

dos2unix
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 12 Jun 2020 07:19:31 +0200
parents b17d03599726
children 4647636334aa
files Deprecated/Applications/Generic/Scene2DInteractor.h Deprecated/Samples/MultiPlatform/BasicScene/BasicScene.cpp Deprecated/Samples/MultiPlatform/BasicScene/BasicScene.h Deprecated/Samples/MultiPlatform/BasicScene/mainQt.cpp Deprecated/Samples/MultiPlatform/BasicScene/mainSdl.cpp Deprecated/Samples/Qt/QStoneOpenGlWidget.cpp Deprecated/Samples/Qt/QStoneOpenGlWidget.h Deprecated/Samples/Qt/Scene2DInteractor.cpp Deprecated/Samples/Qt/Scene2DInteractor.h Deprecated/Samples/Sdl/RadiographyEditor.cpp Framework/Deprecated/Loaders/DicomStructureSetLoader2.cpp Framework/Toolbox/DicomStructurePolygon2.cpp Framework/Toolbox/DicomStructureSetUtils.cpp Framework/Toolbox/TextRenderer.cpp Framework/Toolbox/TextRenderer.h
diffstat 15 files changed, 1608 insertions(+), 1608 deletions(-) [+]
line wrap: on
line diff
--- a/Deprecated/Applications/Generic/Scene2DInteractor.h	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Applications/Generic/Scene2DInteractor.h	Fri Jun 12 07:19:31 2020 +0200
@@ -1,52 +1,52 @@
-/**
- * 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 "../../Framework/Scene2D/PointerEvent.h"
-#include "../../Framework/Scene2DViewport/ViewportController.h"
-//#include "../../Framework/Scene2D/Internals/CompositorHelper.h"
-#include "GuiAdapter.h"
-
-
-namespace OrthancStone
-{
-
-  class Scene2DInteractor
-  {
-  protected:
-    boost::shared_ptr<ViewportController>       viewportController_;
-//    boost::shared_ptr<ICompositor>              compositor_;
-
-  public:
-    Scene2DInteractor(boost::shared_ptr<ViewportController> viewportController) :
-      viewportController_(viewportController)
-    {}
-
-//    void SetCompositor(boost::shared_ptr<ICompositor> compositor)
-//    {
-//      compositor_ = compositor;
-//    }
-
-    virtual bool OnMouseEvent(const GuiAdapterMouseEvent& guiEvent, const PointerEvent& pointerEvent) = 0; // returns true if it has handled the event
-    virtual bool OnKeyboardEvent(const GuiAdapterKeyboardEvent& guiEvent) = 0; // returns true if it has handled the event
-    virtual bool OnWheelEvent(const GuiAdapterWheelEvent& guiEvent) = 0; // returns true if it has handled the event
-
-  };
-}
+/**
+ * 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 "../../Framework/Scene2D/PointerEvent.h"
+#include "../../Framework/Scene2DViewport/ViewportController.h"
+//#include "../../Framework/Scene2D/Internals/CompositorHelper.h"
+#include "GuiAdapter.h"
+
+
+namespace OrthancStone
+{
+
+  class Scene2DInteractor
+  {
+  protected:
+    boost::shared_ptr<ViewportController>       viewportController_;
+//    boost::shared_ptr<ICompositor>              compositor_;
+
+  public:
+    Scene2DInteractor(boost::shared_ptr<ViewportController> viewportController) :
+      viewportController_(viewportController)
+    {}
+
+//    void SetCompositor(boost::shared_ptr<ICompositor> compositor)
+//    {
+//      compositor_ = compositor;
+//    }
+
+    virtual bool OnMouseEvent(const GuiAdapterMouseEvent& guiEvent, const PointerEvent& pointerEvent) = 0; // returns true if it has handled the event
+    virtual bool OnKeyboardEvent(const GuiAdapterKeyboardEvent& guiEvent) = 0; // returns true if it has handled the event
+    virtual bool OnWheelEvent(const GuiAdapterWheelEvent& guiEvent) = 0; // returns true if it has handled the event
+
+  };
+}
--- a/Deprecated/Samples/MultiPlatform/BasicScene/BasicScene.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/MultiPlatform/BasicScene/BasicScene.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,275 +1,275 @@
-/**
- * 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 "BasicScene.h"
-
-// From Stone
-#include "Framework/Scene2D/Scene2D.h"
-#include "Framework/Scene2D/ColorTextureSceneLayer.h"
-#include "Framework/Scene2D/PolylineSceneLayer.h"
-#include "Framework/Scene2D/TextSceneLayer.h"
-
-#include "Framework/Scene2D/PanSceneTracker.h"
-#include "Framework/Scene2D/ZoomSceneTracker.h"
-#include "Framework/Scene2D/RotateSceneTracker.h"
-
-#include "Framework/Scene2D/CairoCompositor.h"
-
-// From Orthanc framework
-#include <Core/Images/Image.h>
-#include <Core/Images/ImageProcessing.h>
-#include <Core/Images/PngWriter.h>
-
-using namespace OrthancStone;
-
-const unsigned int BASIC_SCENE_FONT_SIZE = 32;
-const int BASIC_SCENE_LAYER_POSITION = 150;
-
-void PrepareScene(Scene2D& scene)
-{
-  //Scene2D& scene(*controller->GetScene());
-  // Texture of 2x2 size
-  {
-    Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false);
-
-    uint8_t *p = reinterpret_cast<uint8_t*>(i.GetRow(0));
-    p[0] = 255;
-    p[1] = 0;
-    p[2] = 0;
-
-    p[3] = 0;
-    p[4] = 255;
-    p[5] = 0;
-
-    p = reinterpret_cast<uint8_t*>(i.GetRow(1));
-    p[0] = 0;
-    p[1] = 0;
-    p[2] = 255;
-
-    p[3] = 255;
-    p[4] = 0;
-    p[5] = 0;
-
-    scene.SetLayer(12, new ColorTextureSceneLayer(i));
-
-    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
-    l->SetOrigin(-3, 2);
-    l->SetPixelSpacing(1.5, 1);
-    l->SetAngle(20.0 / 180.0 * 3.14);
-    scene.SetLayer(14, l.release());
-  }
-
-  // Texture of 1x1 size
-  {
-    Orthanc::Image i(Orthanc::PixelFormat_RGB24, 1, 1, false);
-
-    uint8_t *p = reinterpret_cast<uint8_t*>(i.GetRow(0));
-    p[0] = 255;
-    p[1] = 0;
-    p[2] = 0;
-
-    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
-    l->SetOrigin(-2, 1);
-    l->SetAngle(20.0 / 180.0 * 3.14);
-    scene.SetLayer(13, l.release());
-  }
-
-  // Some lines
-  {
-    std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
-
-    layer->SetThickness(1);
-
-    PolylineSceneLayer::Chain chain;
-    chain.push_back(ScenePoint2D(0 - 0.5, 0 - 0.5));
-    chain.push_back(ScenePoint2D(0 - 0.5, 2 - 0.5));
-    chain.push_back(ScenePoint2D(2 - 0.5, 2 - 0.5));
-    chain.push_back(ScenePoint2D(2 - 0.5, 0 - 0.5));
-    layer->AddChain(chain, true, 255, 0, 0);
-
-    chain.clear();
-    chain.push_back(ScenePoint2D(-5, -5));
-    chain.push_back(ScenePoint2D(5, -5));
-    chain.push_back(ScenePoint2D(5, 5));
-    chain.push_back(ScenePoint2D(-5, 5));
-    layer->AddChain(chain, true, 0, 255, 0);
-
-    double dy = 1.01;
-    chain.clear();
-    chain.push_back(ScenePoint2D(-4, -4));
-    chain.push_back(ScenePoint2D(4, -4 + dy));
-    chain.push_back(ScenePoint2D(-4, -4 + 2.0 * dy));
-    chain.push_back(ScenePoint2D(4, 2));
-    layer->AddChain(chain, false, 0, 0, 255);
-
-    //    layer->SetColor(0,255, 255);
-    scene.SetLayer(50, layer.release());
-  }
-
-  // Some text
-  {
-    std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
-    layer->SetText("Hello");
-    scene.SetLayer(100, layer.release());
-  }
-}
-
-#if ORTHANC_SANDBOXED == 0
-void TakeScreenshot(const std::string& target,
-                    const OrthancStone::Scene2D& scene,
-                    unsigned int canvasWidth,
-                    unsigned int canvasHeight)
-{
-  using namespace OrthancStone;
-  // Take a screenshot, then save it as PNG file
-  CairoCompositor compositor(scene, canvasWidth, canvasHeight);
-  compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1);
-  compositor.Refresh();
-
-  Orthanc::ImageAccessor canvas;
-  compositor.GetCanvas().GetReadOnlyAccessor(canvas);
-
-  Orthanc::Image png(Orthanc::PixelFormat_RGB24, canvas.GetWidth(), canvas.GetHeight(), false);
-  Orthanc::ImageProcessing::Convert(png, canvas);
-
-  Orthanc::PngWriter writer;
-  writer.WriteToFile(target, png);
-}
-#endif
-
-void ShowCursorInfo(Scene2D& scene, const PointerEvent& pointerEvent)
-{
-  ScenePoint2D p = pointerEvent.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
-
-  char buf[64];
-  sprintf(buf, "(%0.02f,%0.02f)", p.GetX(), p.GetY());
-
-  if (scene.HasLayer(BASIC_SCENE_LAYER_POSITION))
-  {
-    TextSceneLayer& layer =
-        dynamic_cast<TextSceneLayer&>(scene.GetLayer(BASIC_SCENE_LAYER_POSITION));
-    layer.SetText(buf);
-    layer.SetPosition(p.GetX(), p.GetY());
-  }
-  else
-  {
-    std::unique_ptr<TextSceneLayer>
-        layer(new TextSceneLayer);
-    layer->SetColor(0, 255, 0);
-    layer->SetText(buf);
-    layer->SetBorder(20);
-    layer->SetAnchor(BitmapAnchor_BottomCenter);
-    layer->SetPosition(p.GetX(), p.GetY());
-    scene.SetLayer(BASIC_SCENE_LAYER_POSITION, layer.release());
-  }
-}
-
-
-
-bool BasicScene2DInteractor::OnMouseEvent(const GuiAdapterMouseEvent& event, const PointerEvent& pointerEvent)
-{
-  if (currentTracker_.get() != NULL)
-  {
-    switch (event.type)
-    {
-    case GUIADAPTER_EVENT_MOUSEUP:
-    {
-      currentTracker_->PointerUp(pointerEvent);
-      if (!currentTracker_->IsAlive())
-      {
-        currentTracker_.reset();
-      }
-    };break;
-    case GUIADAPTER_EVENT_MOUSEMOVE:
-    {
-      currentTracker_->PointerMove(pointerEvent);
-    };break;
-    default:
-      return false;
-    }
-    return true;
-  }
-  else if (event.type == GUIADAPTER_EVENT_MOUSEDOWN)
-  {
-    if (event.button == GUIADAPTER_MOUSEBUTTON_LEFT)
-    {
-      currentTracker_.reset(new RotateSceneTracker(viewportController_, pointerEvent));
-    }
-    else if (event.button == GUIADAPTER_MOUSEBUTTON_MIDDLE)
-    {
-      currentTracker_.reset(new PanSceneTracker(viewportController_, pointerEvent));
-    }
-    else if (event.button == GUIADAPTER_MOUSEBUTTON_RIGHT)
-    {
-      currentTracker_.reset(new ZoomSceneTracker(viewportController_, pointerEvent, viewportController_->GetViewport().GetCanvasHeight()));
-    }
-  }
-  else if (event.type == GUIADAPTER_EVENT_MOUSEMOVE)
-  {
-    if (showCursorInfo_)
-    {
-      Scene2D& scene(viewportController_->GetScene());
-      ShowCursorInfo(scene, pointerEvent);
-    }
-    return true;
-  }
-  return false;
-}
-
-bool BasicScene2DInteractor::OnKeyboardEvent(const GuiAdapterKeyboardEvent& guiEvent)
-{
-  if (guiEvent.type == GUIADAPTER_EVENT_KEYDOWN)
-  {
-    switch (guiEvent.sym[0])
-    {
-    case 's':
-    {
-      //viewportController_->FitContent(viewportController_->GetViewport().GetCanvasWidth(), viewportController_->GetViewport().GetCanvasHeight());
-      viewportController_->FitContent();
-      return true;
-    };
-#if ORTHANC_SANDBOXED == 0
-    case 'c':
-    {
-      Scene2D& scene(viewportController_->GetScene());
-      TakeScreenshot("screenshot.png", scene, viewportController_->GetViewport().GetCanvasWidth(), viewportController_->GetViewport().GetCanvasHeight());
-      return true;
-    }
-#endif
-    case 'd':
-    {
-      showCursorInfo_ = !showCursorInfo_;
-      if (!showCursorInfo_)
-      {
-        Scene2D& scene(viewportController_->GetScene());
-        scene.DeleteLayer(BASIC_SCENE_LAYER_POSITION);
-      }
-
-      return true;
-    }
-    }
-  }
-  return false;
-}
-
-bool BasicScene2DInteractor::OnWheelEvent(const GuiAdapterWheelEvent& guiEvent)
-{
-  return false;
-}
+/**
+ * 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 "BasicScene.h"
+
+// From Stone
+#include "Framework/Scene2D/Scene2D.h"
+#include "Framework/Scene2D/ColorTextureSceneLayer.h"
+#include "Framework/Scene2D/PolylineSceneLayer.h"
+#include "Framework/Scene2D/TextSceneLayer.h"
+
+#include "Framework/Scene2D/PanSceneTracker.h"
+#include "Framework/Scene2D/ZoomSceneTracker.h"
+#include "Framework/Scene2D/RotateSceneTracker.h"
+
+#include "Framework/Scene2D/CairoCompositor.h"
+
+// From Orthanc framework
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
+#include <Core/Images/PngWriter.h>
+
+using namespace OrthancStone;
+
+const unsigned int BASIC_SCENE_FONT_SIZE = 32;
+const int BASIC_SCENE_LAYER_POSITION = 150;
+
+void PrepareScene(Scene2D& scene)
+{
+  //Scene2D& scene(*controller->GetScene());
+  // Texture of 2x2 size
+  {
+    Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false);
+
+    uint8_t *p = reinterpret_cast<uint8_t*>(i.GetRow(0));
+    p[0] = 255;
+    p[1] = 0;
+    p[2] = 0;
+
+    p[3] = 0;
+    p[4] = 255;
+    p[5] = 0;
+
+    p = reinterpret_cast<uint8_t*>(i.GetRow(1));
+    p[0] = 0;
+    p[1] = 0;
+    p[2] = 255;
+
+    p[3] = 255;
+    p[4] = 0;
+    p[5] = 0;
+
+    scene.SetLayer(12, new ColorTextureSceneLayer(i));
+
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    l->SetOrigin(-3, 2);
+    l->SetPixelSpacing(1.5, 1);
+    l->SetAngle(20.0 / 180.0 * 3.14);
+    scene.SetLayer(14, l.release());
+  }
+
+  // Texture of 1x1 size
+  {
+    Orthanc::Image i(Orthanc::PixelFormat_RGB24, 1, 1, false);
+
+    uint8_t *p = reinterpret_cast<uint8_t*>(i.GetRow(0));
+    p[0] = 255;
+    p[1] = 0;
+    p[2] = 0;
+
+    std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i));
+    l->SetOrigin(-2, 1);
+    l->SetAngle(20.0 / 180.0 * 3.14);
+    scene.SetLayer(13, l.release());
+  }
+
+  // Some lines
+  {
+    std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
+
+    layer->SetThickness(1);
+
+    PolylineSceneLayer::Chain chain;
+    chain.push_back(ScenePoint2D(0 - 0.5, 0 - 0.5));
+    chain.push_back(ScenePoint2D(0 - 0.5, 2 - 0.5));
+    chain.push_back(ScenePoint2D(2 - 0.5, 2 - 0.5));
+    chain.push_back(ScenePoint2D(2 - 0.5, 0 - 0.5));
+    layer->AddChain(chain, true, 255, 0, 0);
+
+    chain.clear();
+    chain.push_back(ScenePoint2D(-5, -5));
+    chain.push_back(ScenePoint2D(5, -5));
+    chain.push_back(ScenePoint2D(5, 5));
+    chain.push_back(ScenePoint2D(-5, 5));
+    layer->AddChain(chain, true, 0, 255, 0);
+
+    double dy = 1.01;
+    chain.clear();
+    chain.push_back(ScenePoint2D(-4, -4));
+    chain.push_back(ScenePoint2D(4, -4 + dy));
+    chain.push_back(ScenePoint2D(-4, -4 + 2.0 * dy));
+    chain.push_back(ScenePoint2D(4, 2));
+    layer->AddChain(chain, false, 0, 0, 255);
+
+    //    layer->SetColor(0,255, 255);
+    scene.SetLayer(50, layer.release());
+  }
+
+  // Some text
+  {
+    std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
+    layer->SetText("Hello");
+    scene.SetLayer(100, layer.release());
+  }
+}
+
+#if ORTHANC_SANDBOXED == 0
+void TakeScreenshot(const std::string& target,
+                    const OrthancStone::Scene2D& scene,
+                    unsigned int canvasWidth,
+                    unsigned int canvasHeight)
+{
+  using namespace OrthancStone;
+  // Take a screenshot, then save it as PNG file
+  CairoCompositor compositor(scene, canvasWidth, canvasHeight);
+  compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1);
+  compositor.Refresh();
+
+  Orthanc::ImageAccessor canvas;
+  compositor.GetCanvas().GetReadOnlyAccessor(canvas);
+
+  Orthanc::Image png(Orthanc::PixelFormat_RGB24, canvas.GetWidth(), canvas.GetHeight(), false);
+  Orthanc::ImageProcessing::Convert(png, canvas);
+
+  Orthanc::PngWriter writer;
+  writer.WriteToFile(target, png);
+}
+#endif
+
+void ShowCursorInfo(Scene2D& scene, const PointerEvent& pointerEvent)
+{
+  ScenePoint2D p = pointerEvent.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
+
+  char buf[64];
+  sprintf(buf, "(%0.02f,%0.02f)", p.GetX(), p.GetY());
+
+  if (scene.HasLayer(BASIC_SCENE_LAYER_POSITION))
+  {
+    TextSceneLayer& layer =
+        dynamic_cast<TextSceneLayer&>(scene.GetLayer(BASIC_SCENE_LAYER_POSITION));
+    layer.SetText(buf);
+    layer.SetPosition(p.GetX(), p.GetY());
+  }
+  else
+  {
+    std::unique_ptr<TextSceneLayer>
+        layer(new TextSceneLayer);
+    layer->SetColor(0, 255, 0);
+    layer->SetText(buf);
+    layer->SetBorder(20);
+    layer->SetAnchor(BitmapAnchor_BottomCenter);
+    layer->SetPosition(p.GetX(), p.GetY());
+    scene.SetLayer(BASIC_SCENE_LAYER_POSITION, layer.release());
+  }
+}
+
+
+
+bool BasicScene2DInteractor::OnMouseEvent(const GuiAdapterMouseEvent& event, const PointerEvent& pointerEvent)
+{
+  if (currentTracker_.get() != NULL)
+  {
+    switch (event.type)
+    {
+    case GUIADAPTER_EVENT_MOUSEUP:
+    {
+      currentTracker_->PointerUp(pointerEvent);
+      if (!currentTracker_->IsAlive())
+      {
+        currentTracker_.reset();
+      }
+    };break;
+    case GUIADAPTER_EVENT_MOUSEMOVE:
+    {
+      currentTracker_->PointerMove(pointerEvent);
+    };break;
+    default:
+      return false;
+    }
+    return true;
+  }
+  else if (event.type == GUIADAPTER_EVENT_MOUSEDOWN)
+  {
+    if (event.button == GUIADAPTER_MOUSEBUTTON_LEFT)
+    {
+      currentTracker_.reset(new RotateSceneTracker(viewportController_, pointerEvent));
+    }
+    else if (event.button == GUIADAPTER_MOUSEBUTTON_MIDDLE)
+    {
+      currentTracker_.reset(new PanSceneTracker(viewportController_, pointerEvent));
+    }
+    else if (event.button == GUIADAPTER_MOUSEBUTTON_RIGHT)
+    {
+      currentTracker_.reset(new ZoomSceneTracker(viewportController_, pointerEvent, viewportController_->GetViewport().GetCanvasHeight()));
+    }
+  }
+  else if (event.type == GUIADAPTER_EVENT_MOUSEMOVE)
+  {
+    if (showCursorInfo_)
+    {
+      Scene2D& scene(viewportController_->GetScene());
+      ShowCursorInfo(scene, pointerEvent);
+    }
+    return true;
+  }
+  return false;
+}
+
+bool BasicScene2DInteractor::OnKeyboardEvent(const GuiAdapterKeyboardEvent& guiEvent)
+{
+  if (guiEvent.type == GUIADAPTER_EVENT_KEYDOWN)
+  {
+    switch (guiEvent.sym[0])
+    {
+    case 's':
+    {
+      //viewportController_->FitContent(viewportController_->GetViewport().GetCanvasWidth(), viewportController_->GetViewport().GetCanvasHeight());
+      viewportController_->FitContent();
+      return true;
+    };
+#if ORTHANC_SANDBOXED == 0
+    case 'c':
+    {
+      Scene2D& scene(viewportController_->GetScene());
+      TakeScreenshot("screenshot.png", scene, viewportController_->GetViewport().GetCanvasWidth(), viewportController_->GetViewport().GetCanvasHeight());
+      return true;
+    }
+#endif
+    case 'd':
+    {
+      showCursorInfo_ = !showCursorInfo_;
+      if (!showCursorInfo_)
+      {
+        Scene2D& scene(viewportController_->GetScene());
+        scene.DeleteLayer(BASIC_SCENE_LAYER_POSITION);
+      }
+
+      return true;
+    }
+    }
+  }
+  return false;
+}
+
+bool BasicScene2DInteractor::OnWheelEvent(const GuiAdapterWheelEvent& guiEvent)
+{
+  return false;
+}
--- a/Deprecated/Samples/MultiPlatform/BasicScene/BasicScene.h	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/MultiPlatform/BasicScene/BasicScene.h	Fri Jun 12 07:19:31 2020 +0200
@@ -1,55 +1,55 @@
-/**
- * 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 <boost/shared_ptr.hpp>
-#include "Framework/Scene2DViewport/ViewportController.h"
-#include "Framework/Scene2D/Scene2D.h"
-
-extern const unsigned int BASIC_SCENE_FONT_SIZE;
-extern const int BASIC_SCENE_LAYER_POSITION;
-
-extern void PrepareScene(OrthancStone::Scene2D& scene);
-extern void TakeScreenshot(const std::string& target,
-                           const OrthancStone::Scene2D& scene,
-                           unsigned int canvasWidth,
-                           unsigned int canvasHeight);
-
-
-#include "Applications/Generic/Scene2DInteractor.h"
-#include "Framework/Scene2DViewport/IFlexiblePointerTracker.h"
-
-
-class BasicScene2DInteractor : public OrthancStone::Scene2DInteractor
-{
-  boost::shared_ptr<OrthancStone::IFlexiblePointerTracker>  currentTracker_;
-  bool                                                      showCursorInfo_;
-public:
-  BasicScene2DInteractor(boost::shared_ptr<OrthancStone::ViewportController> viewportController) :
-    Scene2DInteractor(viewportController),
-    showCursorInfo_(false)
-  {}
-
-  virtual bool OnMouseEvent(const OrthancStone::GuiAdapterMouseEvent& event, const OrthancStone::PointerEvent& pointerEvent) override;
-  virtual bool OnKeyboardEvent(const OrthancStone::GuiAdapterKeyboardEvent& guiEvent) override;
-  virtual bool OnWheelEvent(const OrthancStone::GuiAdapterWheelEvent& guiEvent) override;
-};
-
+/**
+ * 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 <boost/shared_ptr.hpp>
+#include "Framework/Scene2DViewport/ViewportController.h"
+#include "Framework/Scene2D/Scene2D.h"
+
+extern const unsigned int BASIC_SCENE_FONT_SIZE;
+extern const int BASIC_SCENE_LAYER_POSITION;
+
+extern void PrepareScene(OrthancStone::Scene2D& scene);
+extern void TakeScreenshot(const std::string& target,
+                           const OrthancStone::Scene2D& scene,
+                           unsigned int canvasWidth,
+                           unsigned int canvasHeight);
+
+
+#include "Applications/Generic/Scene2DInteractor.h"
+#include "Framework/Scene2DViewport/IFlexiblePointerTracker.h"
+
+
+class BasicScene2DInteractor : public OrthancStone::Scene2DInteractor
+{
+  boost::shared_ptr<OrthancStone::IFlexiblePointerTracker>  currentTracker_;
+  bool                                                      showCursorInfo_;
+public:
+  BasicScene2DInteractor(boost::shared_ptr<OrthancStone::ViewportController> viewportController) :
+    Scene2DInteractor(viewportController),
+    showCursorInfo_(false)
+  {}
+
+  virtual bool OnMouseEvent(const OrthancStone::GuiAdapterMouseEvent& event, const OrthancStone::PointerEvent& pointerEvent) override;
+  virtual bool OnKeyboardEvent(const OrthancStone::GuiAdapterKeyboardEvent& guiEvent) override;
+  virtual bool OnWheelEvent(const OrthancStone::GuiAdapterWheelEvent& guiEvent) override;
+};
+
--- a/Deprecated/Samples/MultiPlatform/BasicScene/mainQt.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/MultiPlatform/BasicScene/mainQt.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,103 +1,103 @@
-/**
- * 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/>.
- **/
-
-#define GLEW_STATIC 1
-// From Stone
-#include "../../Framework/OpenGL/OpenGLIncludes.h"
-#include "../../Applications/Sdl/SdlWindow.h"
-#include "../../Framework/Scene2D/CairoCompositor.h"
-#include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
-#include "../../Framework/Scene2D/OpenGLCompositor.h"
-#include "../../Framework/Scene2D/PanSceneTracker.h"
-#include "../../Framework/Scene2D/RotateSceneTracker.h"
-#include "../../Framework/Scene2D/Scene2D.h"
-#include "../../Framework/Scene2D/ZoomSceneTracker.h"
-#include "../../Framework/Scene2DViewport/ViewportController.h"
-#include "../../Framework/Scene2DViewport/UndoStack.h"
-
-#include "../../Framework/StoneInitialization.h"
-#include "../../Framework/Messages/MessageBroker.h"
-
-// From Orthanc framework
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <Core/Images/Image.h>
-#include <Core/Images/ImageProcessing.h>
-#include <Core/Images/PngWriter.h>
-
-#include <boost/make_shared.hpp>
-#include <boost/ref.hpp>
-#include "EmbeddedResources.h"
-
-#include <stdio.h>
-#include <QDebug>
-#include <QWindow>
-
-#include "BasicScene.h"
-
-
-using namespace OrthancStone;
-
-
-
-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 );
-  }
-}
-
-extern void InitGL();
-
-#include <QApplication>
-#include "BasicSceneWindow.h"
-
-int main(int argc, char* argv[])
-{
-  QApplication a(argc, argv);
-
-  OrthancStone::Samples::BasicSceneWindow window;
-  window.show();
-  window.GetOpenGlWidget().Init();
-
-  MessageBroker broker;
-  boost::shared_ptr<UndoStack> undoStack(new UndoStack);
-  boost::shared_ptr<ViewportController> controller = boost::make_shared<ViewportController>(undoStack, boost::ref(broker), window.GetOpenGlWidget());
-  PrepareScene(controller->GetScene());
-
-  window.GetOpenGlWidget().GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                     BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1);
-
-  boost::shared_ptr<OrthancStone::Scene2DInteractor> interactor(new BasicScene2DInteractor(controller));
-  window.GetOpenGlWidget().SetInteractor(interactor);
-
-  controller->FitContent();
-
-  return a.exec();
-}
+/**
+ * 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/>.
+ **/
+
+#define GLEW_STATIC 1
+// From Stone
+#include "../../Framework/OpenGL/OpenGLIncludes.h"
+#include "../../Applications/Sdl/SdlWindow.h"
+#include "../../Framework/Scene2D/CairoCompositor.h"
+#include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
+#include "../../Framework/Scene2D/OpenGLCompositor.h"
+#include "../../Framework/Scene2D/PanSceneTracker.h"
+#include "../../Framework/Scene2D/RotateSceneTracker.h"
+#include "../../Framework/Scene2D/Scene2D.h"
+#include "../../Framework/Scene2D/ZoomSceneTracker.h"
+#include "../../Framework/Scene2DViewport/ViewportController.h"
+#include "../../Framework/Scene2DViewport/UndoStack.h"
+
+#include "../../Framework/StoneInitialization.h"
+#include "../../Framework/Messages/MessageBroker.h"
+
+// From Orthanc framework
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
+#include <Core/Images/PngWriter.h>
+
+#include <boost/make_shared.hpp>
+#include <boost/ref.hpp>
+#include "EmbeddedResources.h"
+
+#include <stdio.h>
+#include <QDebug>
+#include <QWindow>
+
+#include "BasicScene.h"
+
+
+using namespace OrthancStone;
+
+
+
+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 );
+  }
+}
+
+extern void InitGL();
+
+#include <QApplication>
+#include "BasicSceneWindow.h"
+
+int main(int argc, char* argv[])
+{
+  QApplication a(argc, argv);
+
+  OrthancStone::Samples::BasicSceneWindow window;
+  window.show();
+  window.GetOpenGlWidget().Init();
+
+  MessageBroker broker;
+  boost::shared_ptr<UndoStack> undoStack(new UndoStack);
+  boost::shared_ptr<ViewportController> controller = boost::make_shared<ViewportController>(undoStack, boost::ref(broker), window.GetOpenGlWidget());
+  PrepareScene(controller->GetScene());
+
+  window.GetOpenGlWidget().GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
+                     BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1);
+
+  boost::shared_ptr<OrthancStone::Scene2DInteractor> interactor(new BasicScene2DInteractor(controller));
+  window.GetOpenGlWidget().SetInteractor(interactor);
+
+  controller->FitContent();
+
+  return a.exec();
+}
--- a/Deprecated/Samples/MultiPlatform/BasicScene/mainSdl.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/MultiPlatform/BasicScene/mainSdl.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,199 +1,199 @@
-/**
- * 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/>.
- **/
-
-
-// From Stone
-#include "Framework/Viewport/SdlViewport.h"
-#include "Framework/Scene2D/OpenGLCompositor.h"
-#include "Framework/Scene2DViewport/UndoStack.h"
-#include "Framework/StoneInitialization.h"
-#include "Framework/Messages/MessageBroker.h"
-
-// From Orthanc framework
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/make_shared.hpp>
-#include <boost/ref.hpp>
-
-#include <SDL.h>
-#include <stdio.h>
-
-
-#include "BasicScene.h"
-
-using namespace OrthancStone;
-
-boost::shared_ptr<BasicScene2DInteractor> interactor;
-
-void HandleApplicationEvent(boost::shared_ptr<OrthancStone::ViewportController> controller,
-                            const SDL_Event& event)
-{
-  using namespace OrthancStone;
-  Scene2D& scene(controller->GetScene());
-  if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEMOTION)
-  {
-    // TODO: this code is copy/pasted from GuiAdapter::Run() -> find the right place
-    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 guiEvent;
-    ConvertFromPlatform(guiEvent, ctrlPressed, shiftPressed, altPressed, event);
-    PointerEvent pointerEvent;
-    pointerEvent.AddPosition(controller->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y));
-
-    interactor->OnMouseEvent(guiEvent, pointerEvent);
-    return;
-  }
-  else if ((event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) && event.key.repeat == 0  /* Ignore key bounce */)
-  {
-    GuiAdapterKeyboardEvent guiEvent;
-    ConvertFromPlatform(guiEvent, event);
-
-    interactor->OnKeyboardEvent(guiEvent);
-  }
-
-}
-
-
-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 );
-  }
-}
-
-
-void Run(boost::shared_ptr<OrthancStone::ViewportController> controller)
-{
-  SdlViewport& sdlViewport = dynamic_cast<SdlViewport&>(controller->GetViewport());
-
-  glEnable(GL_DEBUG_OUTPUT);
-  glDebugMessageCallback(OpenGLMessageCallback, 0);
-
-  controller->GetViewport().GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                     BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1);
-
-  controller->GetViewport().Refresh();
-  controller->FitContent();
-
-
-  bool stop = false;
-  while (!stop)
-  {
-    controller->GetViewport().Refresh();
-
-    SDL_Event event;
-    while (!stop &&
-           SDL_PollEvent(&event))
-    {
-      if (event.type == SDL_QUIT)
-      {
-        stop = true;
-        break;
-      }
-      else if (event.type == SDL_WINDOWEVENT &&
-               event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
-      {
-        sdlViewport.UpdateSize(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:
-            sdlViewport.GetWindow().ToggleMaximize();
-            break;
-              
-          case SDLK_q:
-            stop = true;
-            break;
-
-          default:
-            break;
-        }
-      }
-      
-      HandleApplicationEvent(controller, event);
-    }
-
-    SDL_Delay(1);
-  }
-  interactor.reset();
-}
-
-
-
-
-/**
- * IMPORTANT: The full arguments to "main()" are needed for SDL on
- * Windows. Otherwise, one gets the linking error "undefined reference
- * to `SDL_main'". https://wiki.libsdl.org/FAQWindows
- **/
-int main(int argc, char* argv[])
-{
-  using namespace OrthancStone;
-  StoneInitialize();
-  Orthanc::Logging::EnableInfoLevel(true);
-
-  try
-  {
-    SdlOpenGLViewport viewport("Hello", 1024, 768);
-    MessageBroker broker;
-    boost::shared_ptr<UndoStack> undoStack(new UndoStack);
-    boost::shared_ptr<ViewportController> controller = boost::make_shared<ViewportController>(undoStack, boost::ref(broker), boost::ref(viewport));
-    interactor.reset(new BasicScene2DInteractor(controller));
-    PrepareScene(controller->GetScene());
-    Run(controller);
-  }
-  catch (Orthanc::OrthancException& e)
-  {
-    LOG(ERROR) << "EXCEPTION: " << e.What();
-  }
-
-  StoneFinalize();
-
-  return 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/>.
+ **/
+
+
+// From Stone
+#include "Framework/Viewport/SdlViewport.h"
+#include "Framework/Scene2D/OpenGLCompositor.h"
+#include "Framework/Scene2DViewport/UndoStack.h"
+#include "Framework/StoneInitialization.h"
+#include "Framework/Messages/MessageBroker.h"
+
+// From Orthanc framework
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/make_shared.hpp>
+#include <boost/ref.hpp>
+
+#include <SDL.h>
+#include <stdio.h>
+
+
+#include "BasicScene.h"
+
+using namespace OrthancStone;
+
+boost::shared_ptr<BasicScene2DInteractor> interactor;
+
+void HandleApplicationEvent(boost::shared_ptr<OrthancStone::ViewportController> controller,
+                            const SDL_Event& event)
+{
+  using namespace OrthancStone;
+  Scene2D& scene(controller->GetScene());
+  if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEMOTION)
+  {
+    // TODO: this code is copy/pasted from GuiAdapter::Run() -> find the right place
+    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 guiEvent;
+    ConvertFromPlatform(guiEvent, ctrlPressed, shiftPressed, altPressed, event);
+    PointerEvent pointerEvent;
+    pointerEvent.AddPosition(controller->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y));
+
+    interactor->OnMouseEvent(guiEvent, pointerEvent);
+    return;
+  }
+  else if ((event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) && event.key.repeat == 0  /* Ignore key bounce */)
+  {
+    GuiAdapterKeyboardEvent guiEvent;
+    ConvertFromPlatform(guiEvent, event);
+
+    interactor->OnKeyboardEvent(guiEvent);
+  }
+
+}
+
+
+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 );
+  }
+}
+
+
+void Run(boost::shared_ptr<OrthancStone::ViewportController> controller)
+{
+  SdlViewport& sdlViewport = dynamic_cast<SdlViewport&>(controller->GetViewport());
+
+  glEnable(GL_DEBUG_OUTPUT);
+  glDebugMessageCallback(OpenGLMessageCallback, 0);
+
+  controller->GetViewport().GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
+                     BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1);
+
+  controller->GetViewport().Refresh();
+  controller->FitContent();
+
+
+  bool stop = false;
+  while (!stop)
+  {
+    controller->GetViewport().Refresh();
+
+    SDL_Event event;
+    while (!stop &&
+           SDL_PollEvent(&event))
+    {
+      if (event.type == SDL_QUIT)
+      {
+        stop = true;
+        break;
+      }
+      else if (event.type == SDL_WINDOWEVENT &&
+               event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
+      {
+        sdlViewport.UpdateSize(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:
+            sdlViewport.GetWindow().ToggleMaximize();
+            break;
+              
+          case SDLK_q:
+            stop = true;
+            break;
+
+          default:
+            break;
+        }
+      }
+      
+      HandleApplicationEvent(controller, event);
+    }
+
+    SDL_Delay(1);
+  }
+  interactor.reset();
+}
+
+
+
+
+/**
+ * IMPORTANT: The full arguments to "main()" are needed for SDL on
+ * Windows. Otherwise, one gets the linking error "undefined reference
+ * to `SDL_main'". https://wiki.libsdl.org/FAQWindows
+ **/
+int main(int argc, char* argv[])
+{
+  using namespace OrthancStone;
+  StoneInitialize();
+  Orthanc::Logging::EnableInfoLevel(true);
+
+  try
+  {
+    SdlOpenGLViewport viewport("Hello", 1024, 768);
+    MessageBroker broker;
+    boost::shared_ptr<UndoStack> undoStack(new UndoStack);
+    boost::shared_ptr<ViewportController> controller = boost::make_shared<ViewportController>(undoStack, boost::ref(broker), boost::ref(viewport));
+    interactor.reset(new BasicScene2DInteractor(controller));
+    PrepareScene(controller->GetScene());
+    Run(controller);
+  }
+  catch (Orthanc::OrthancException& e)
+  {
+    LOG(ERROR) << "EXCEPTION: " << e.What();
+  }
+
+  StoneFinalize();
+
+  return 0;
+}
--- a/Deprecated/Samples/Qt/QStoneOpenGlWidget.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/Qt/QStoneOpenGlWidget.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,192 +1,192 @@
-/**
- * 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 "../../Framework/OpenGL/OpenGLIncludes.h"
-#include "QStoneOpenGlWidget.h"
-
-#include <QMouseEvent>
-
-using namespace OrthancStone;
-
-void QStoneOpenGlWidget::initializeGL()
-{
-  glewInit();
-}
-
-void QStoneOpenGlWidget::MakeCurrent()
-{
-  this->makeCurrent();
-}
-
-void QStoneOpenGlWidget::resizeGL(int w, int h)
-{
-
-}
-
-void QStoneOpenGlWidget::paintGL()
-{
-  if (compositor_)
-  {
-    compositor_->Refresh();
-  }
-  doneCurrent();
-}
-
-void ConvertFromPlatform(
-    OrthancStone::GuiAdapterMouseEvent& guiEvent,
-    PointerEvent& pointerEvent,
-    const QMouseEvent& qtEvent,
-    const IViewport& viewport)
-{
-  guiEvent.targetX = qtEvent.x();
-  guiEvent.targetY = qtEvent.y();
-  pointerEvent.AddPosition(viewport.GetPixelCenterCoordinates(guiEvent.targetX, guiEvent.targetY));
-
-  switch (qtEvent.button())
-  {
-  case Qt::LeftButton: guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_LEFT; break;
-  case Qt::MiddleButton: guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_MIDDLE; break;
-  case Qt::RightButton: guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_RIGHT; break;
-  default:
-    guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_LEFT;
-  }
-
-  if (qtEvent.modifiers().testFlag(Qt::ShiftModifier))
-  {
-    guiEvent.shiftKey = true;
-  }
-  if (qtEvent.modifiers().testFlag(Qt::ControlModifier))
-  {
-    guiEvent.ctrlKey = true;
-  }
-  if (qtEvent.modifiers().testFlag(Qt::AltModifier))
-  {
-    guiEvent.altKey = true;
-  }
-}
-
-void QStoneOpenGlWidget::mouseEvent(QMouseEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType)
-{
-  OrthancStone::GuiAdapterMouseEvent guiEvent;
-  PointerEvent pointerEvent;
-  ConvertFromPlatform(guiEvent, pointerEvent, *qtEvent, *this);
-  guiEvent.type = guiEventType;
-
-  if (sceneInteractor_.get() != NULL && compositor_.get() != NULL)
-  {
-    sceneInteractor_->OnMouseEvent(guiEvent, pointerEvent);
-  }
-
-  // force redraw of the OpenGL widget
-  update();
-}
-
-void QStoneOpenGlWidget::mousePressEvent(QMouseEvent* qtEvent)
-{
-  mouseEvent(qtEvent, GUIADAPTER_EVENT_MOUSEDOWN);
-}
-
-void QStoneOpenGlWidget::mouseMoveEvent(QMouseEvent* qtEvent)
-{
-  mouseEvent(qtEvent, GUIADAPTER_EVENT_MOUSEMOVE);
-}
-
-void QStoneOpenGlWidget::mouseReleaseEvent(QMouseEvent* qtEvent)
-{
-  mouseEvent(qtEvent, GUIADAPTER_EVENT_MOUSEUP);
-}
-
-void ConvertFromPlatform(
-    OrthancStone::GuiAdapterKeyboardEvent& guiEvent,
-    const QKeyEvent& qtEvent)
-{
-  if (qtEvent.text().length() > 0)
-  {
-    guiEvent.sym[0] = qtEvent.text()[0].cell();
-  }
-  else
-  {
-    guiEvent.sym[0] = 0;
-  }
-  guiEvent.sym[1] = 0;
-
-  if (qtEvent.modifiers().testFlag(Qt::ShiftModifier))
-  {
-    guiEvent.shiftKey = true;
-  }
-  if (qtEvent.modifiers().testFlag(Qt::ControlModifier))
-  {
-    guiEvent.ctrlKey = true;
-  }
-  if (qtEvent.modifiers().testFlag(Qt::AltModifier))
-  {
-    guiEvent.altKey = true;
-  }
-
-}
-
-
-bool QStoneOpenGlWidget::keyEvent(QKeyEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType)
-{
-  bool handled = false;
-  OrthancStone::GuiAdapterKeyboardEvent guiEvent;
-  ConvertFromPlatform(guiEvent, *qtEvent);
-  guiEvent.type = guiEventType;
-
-  if (sceneInteractor_.get() != NULL && compositor_.get() != NULL)
-  {
-    handled = sceneInteractor_->OnKeyboardEvent(guiEvent);
-
-    if (handled)
-    {
-      // force redraw of the OpenGL widget
-      update();
-    }
-  }
-  return handled;
-}
-
-void QStoneOpenGlWidget::keyPressEvent(QKeyEvent *qtEvent)
-{
-  bool handled = keyEvent(qtEvent, GUIADAPTER_EVENT_KEYDOWN);
-  if (!handled)
-  {
-    QOpenGLWidget::keyPressEvent(qtEvent);
-  }
-}
-
-void QStoneOpenGlWidget::keyReleaseEvent(QKeyEvent *qtEvent)
-{
-  bool handled = keyEvent(qtEvent, GUIADAPTER_EVENT_KEYUP);
-  if (!handled)
-  {
-    QOpenGLWidget::keyPressEvent(qtEvent);
-  }
-}
-
-void QStoneOpenGlWidget::wheelEvent(QWheelEvent *qtEvent)
-{
-  OrthancStone::GuiAdapterWheelEvent guiEvent;
-  throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-
-  // force redraw of the OpenGL widget
-  update();
-}
+/**
+ * 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 "../../Framework/OpenGL/OpenGLIncludes.h"
+#include "QStoneOpenGlWidget.h"
+
+#include <QMouseEvent>
+
+using namespace OrthancStone;
+
+void QStoneOpenGlWidget::initializeGL()
+{
+  glewInit();
+}
+
+void QStoneOpenGlWidget::MakeCurrent()
+{
+  this->makeCurrent();
+}
+
+void QStoneOpenGlWidget::resizeGL(int w, int h)
+{
+
+}
+
+void QStoneOpenGlWidget::paintGL()
+{
+  if (compositor_)
+  {
+    compositor_->Refresh();
+  }
+  doneCurrent();
+}
+
+void ConvertFromPlatform(
+    OrthancStone::GuiAdapterMouseEvent& guiEvent,
+    PointerEvent& pointerEvent,
+    const QMouseEvent& qtEvent,
+    const IViewport& viewport)
+{
+  guiEvent.targetX = qtEvent.x();
+  guiEvent.targetY = qtEvent.y();
+  pointerEvent.AddPosition(viewport.GetPixelCenterCoordinates(guiEvent.targetX, guiEvent.targetY));
+
+  switch (qtEvent.button())
+  {
+  case Qt::LeftButton: guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_LEFT; break;
+  case Qt::MiddleButton: guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_MIDDLE; break;
+  case Qt::RightButton: guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_RIGHT; break;
+  default:
+    guiEvent.button = OrthancStone::GUIADAPTER_MOUSEBUTTON_LEFT;
+  }
+
+  if (qtEvent.modifiers().testFlag(Qt::ShiftModifier))
+  {
+    guiEvent.shiftKey = true;
+  }
+  if (qtEvent.modifiers().testFlag(Qt::ControlModifier))
+  {
+    guiEvent.ctrlKey = true;
+  }
+  if (qtEvent.modifiers().testFlag(Qt::AltModifier))
+  {
+    guiEvent.altKey = true;
+  }
+}
+
+void QStoneOpenGlWidget::mouseEvent(QMouseEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType)
+{
+  OrthancStone::GuiAdapterMouseEvent guiEvent;
+  PointerEvent pointerEvent;
+  ConvertFromPlatform(guiEvent, pointerEvent, *qtEvent, *this);
+  guiEvent.type = guiEventType;
+
+  if (sceneInteractor_.get() != NULL && compositor_.get() != NULL)
+  {
+    sceneInteractor_->OnMouseEvent(guiEvent, pointerEvent);
+  }
+
+  // force redraw of the OpenGL widget
+  update();
+}
+
+void QStoneOpenGlWidget::mousePressEvent(QMouseEvent* qtEvent)
+{
+  mouseEvent(qtEvent, GUIADAPTER_EVENT_MOUSEDOWN);
+}
+
+void QStoneOpenGlWidget::mouseMoveEvent(QMouseEvent* qtEvent)
+{
+  mouseEvent(qtEvent, GUIADAPTER_EVENT_MOUSEMOVE);
+}
+
+void QStoneOpenGlWidget::mouseReleaseEvent(QMouseEvent* qtEvent)
+{
+  mouseEvent(qtEvent, GUIADAPTER_EVENT_MOUSEUP);
+}
+
+void ConvertFromPlatform(
+    OrthancStone::GuiAdapterKeyboardEvent& guiEvent,
+    const QKeyEvent& qtEvent)
+{
+  if (qtEvent.text().length() > 0)
+  {
+    guiEvent.sym[0] = qtEvent.text()[0].cell();
+  }
+  else
+  {
+    guiEvent.sym[0] = 0;
+  }
+  guiEvent.sym[1] = 0;
+
+  if (qtEvent.modifiers().testFlag(Qt::ShiftModifier))
+  {
+    guiEvent.shiftKey = true;
+  }
+  if (qtEvent.modifiers().testFlag(Qt::ControlModifier))
+  {
+    guiEvent.ctrlKey = true;
+  }
+  if (qtEvent.modifiers().testFlag(Qt::AltModifier))
+  {
+    guiEvent.altKey = true;
+  }
+
+}
+
+
+bool QStoneOpenGlWidget::keyEvent(QKeyEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType)
+{
+  bool handled = false;
+  OrthancStone::GuiAdapterKeyboardEvent guiEvent;
+  ConvertFromPlatform(guiEvent, *qtEvent);
+  guiEvent.type = guiEventType;
+
+  if (sceneInteractor_.get() != NULL && compositor_.get() != NULL)
+  {
+    handled = sceneInteractor_->OnKeyboardEvent(guiEvent);
+
+    if (handled)
+    {
+      // force redraw of the OpenGL widget
+      update();
+    }
+  }
+  return handled;
+}
+
+void QStoneOpenGlWidget::keyPressEvent(QKeyEvent *qtEvent)
+{
+  bool handled = keyEvent(qtEvent, GUIADAPTER_EVENT_KEYDOWN);
+  if (!handled)
+  {
+    QOpenGLWidget::keyPressEvent(qtEvent);
+  }
+}
+
+void QStoneOpenGlWidget::keyReleaseEvent(QKeyEvent *qtEvent)
+{
+  bool handled = keyEvent(qtEvent, GUIADAPTER_EVENT_KEYUP);
+  if (!handled)
+  {
+    QOpenGLWidget::keyPressEvent(qtEvent);
+  }
+}
+
+void QStoneOpenGlWidget::wheelEvent(QWheelEvent *qtEvent)
+{
+  OrthancStone::GuiAdapterWheelEvent guiEvent;
+  throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+
+  // force redraw of the OpenGL widget
+  update();
+}
--- a/Deprecated/Samples/Qt/QStoneOpenGlWidget.h	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/Qt/QStoneOpenGlWidget.h	Fri Jun 12 07:19:31 2020 +0200
@@ -1,111 +1,111 @@
-/**
- * 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 "../../Framework/OpenGL/OpenGLIncludes.h"
-#include <QOpenGLWidget>
-#include <QOpenGLFunctions>
-#include <QOpenGLContext>
-
-#include <boost/shared_ptr.hpp>
-#include "../../Framework/OpenGL/IOpenGLContext.h"
-#include "../../Framework/Scene2D/OpenGLCompositor.h"
-#include "../../Framework/Viewport/ViewportBase.h"
-#include "../../Applications/Generic/Scene2DInteractor.h"
-
-namespace OrthancStone
-{
-  class QStoneOpenGlWidget :
-      public QOpenGLWidget,
-      public OpenGL::IOpenGLContext,
-      public ViewportBase
-  {
-    std::unique_ptr<OrthancStone::OpenGLCompositor> compositor_;
-    boost::shared_ptr<Scene2DInteractor> sceneInteractor_;
-    QOpenGLContext                        openGlContext_;
-
-  public:
-    QStoneOpenGlWidget(QWidget *parent) :
-      QOpenGLWidget(parent),
-      ViewportBase("QtStoneOpenGlWidget")  // TODO: we shall be able to define a name but construction time is too early !
-    {
-      setFocusPolicy(Qt::StrongFocus);  // to enable keyPressEvent
-      setMouseTracking(true);           // to enable mouseMoveEvent event when no button is pressed
-    }
-
-    void Init()
-    {
-      QSurfaceFormat requestedFormat;
-      requestedFormat.setVersion( 2, 0 );
-      openGlContext_.setFormat( requestedFormat );
-      openGlContext_.create();
-      openGlContext_.makeCurrent(context()->surface());
-
-      compositor_.reset(new OpenGLCompositor(*this, GetScene()));
-    }
-
-  protected:
-
-    //**** QWidget overrides
-    void initializeGL() override;
-    void resizeGL(int w, int h) override;
-    void paintGL() override;
-
-    void mousePressEvent(QMouseEvent* event) override;
-    void mouseMoveEvent(QMouseEvent* event) override;
-    void mouseReleaseEvent(QMouseEvent* event) override;
-    void keyPressEvent(QKeyEvent* event) override;
-    void keyReleaseEvent(QKeyEvent *event) override;
-    void wheelEvent(QWheelEvent* event) override;
-
-    //**** IOpenGLContext overrides
-
-    virtual void MakeCurrent() override;
-    virtual void SwapBuffer() override {}
-
-    virtual unsigned int GetCanvasWidth() const override
-    {
-      return this->width();
-    }
-
-    virtual unsigned int GetCanvasHeight() const override
-    {
-      return this->height();
-    }
-
-  public:
-
-    void SetInteractor(boost::shared_ptr<Scene2DInteractor> sceneInteractor)
-    {
-      sceneInteractor_ = sceneInteractor;
-    }
-
-    virtual ICompositor& GetCompositor()
-    {
-      return *compositor_;
-    }
-
-  protected:
-    void mouseEvent(QMouseEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType);
-    bool keyEvent(QKeyEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType);
-
-  };
-}
+/**
+ * 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 "../../Framework/OpenGL/OpenGLIncludes.h"
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
+#include <QOpenGLContext>
+
+#include <boost/shared_ptr.hpp>
+#include "../../Framework/OpenGL/IOpenGLContext.h"
+#include "../../Framework/Scene2D/OpenGLCompositor.h"
+#include "../../Framework/Viewport/ViewportBase.h"
+#include "../../Applications/Generic/Scene2DInteractor.h"
+
+namespace OrthancStone
+{
+  class QStoneOpenGlWidget :
+      public QOpenGLWidget,
+      public OpenGL::IOpenGLContext,
+      public ViewportBase
+  {
+    std::unique_ptr<OrthancStone::OpenGLCompositor> compositor_;
+    boost::shared_ptr<Scene2DInteractor> sceneInteractor_;
+    QOpenGLContext                        openGlContext_;
+
+  public:
+    QStoneOpenGlWidget(QWidget *parent) :
+      QOpenGLWidget(parent),
+      ViewportBase("QtStoneOpenGlWidget")  // TODO: we shall be able to define a name but construction time is too early !
+    {
+      setFocusPolicy(Qt::StrongFocus);  // to enable keyPressEvent
+      setMouseTracking(true);           // to enable mouseMoveEvent event when no button is pressed
+    }
+
+    void Init()
+    {
+      QSurfaceFormat requestedFormat;
+      requestedFormat.setVersion( 2, 0 );
+      openGlContext_.setFormat( requestedFormat );
+      openGlContext_.create();
+      openGlContext_.makeCurrent(context()->surface());
+
+      compositor_.reset(new OpenGLCompositor(*this, GetScene()));
+    }
+
+  protected:
+
+    //**** QWidget overrides
+    void initializeGL() override;
+    void resizeGL(int w, int h) override;
+    void paintGL() override;
+
+    void mousePressEvent(QMouseEvent* event) override;
+    void mouseMoveEvent(QMouseEvent* event) override;
+    void mouseReleaseEvent(QMouseEvent* event) override;
+    void keyPressEvent(QKeyEvent* event) override;
+    void keyReleaseEvent(QKeyEvent *event) override;
+    void wheelEvent(QWheelEvent* event) override;
+
+    //**** IOpenGLContext overrides
+
+    virtual void MakeCurrent() override;
+    virtual void SwapBuffer() override {}
+
+    virtual unsigned int GetCanvasWidth() const override
+    {
+      return this->width();
+    }
+
+    virtual unsigned int GetCanvasHeight() const override
+    {
+      return this->height();
+    }
+
+  public:
+
+    void SetInteractor(boost::shared_ptr<Scene2DInteractor> sceneInteractor)
+    {
+      sceneInteractor_ = sceneInteractor;
+    }
+
+    virtual ICompositor& GetCompositor()
+    {
+      return *compositor_;
+    }
+
+  protected:
+    void mouseEvent(QMouseEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType);
+    bool keyEvent(QKeyEvent* qtEvent, OrthancStone::GuiAdapterHidEventType guiEventType);
+
+  };
+}
--- a/Deprecated/Samples/Qt/Scene2DInteractor.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/Qt/Scene2DInteractor.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,93 +1,93 @@
-/**
- * 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 "Scene2DInteractor.h"
-
-#include "../../Framework/Scene2D/PanSceneTracker.h"
-#include "../../Framework/Scene2D/ZoomSceneTracker.h"
-#include "../../Framework/Scene2D/RotateSceneTracker.h"
-
-
-namespace OrthancStone
-{
-
-}
-
-using namespace OrthancStone;
-
-
-bool BasicScene2DInteractor::OnMouseEvent(const GuiAdapterMouseEvent& event, const PointerEvent& pointerEvent)
-{
-  if (currentTracker_.get() != NULL)
-  {
-    switch (event.type)
-    {
-    case GUIADAPTER_EVENT_MOUSEUP:
-    {
-      currentTracker_->PointerUp(pointerEvent);
-      if (!currentTracker_->IsAlive())
-      {
-        currentTracker_.reset();
-      }
-    };break;
-    case GUIADAPTER_EVENT_MOUSEMOVE:
-    {
-      currentTracker_->PointerMove(pointerEvent);
-    };break;
-    }
-    return true;
-  }
-  else
-  {
-    if (event.button == GUIADAPTER_MOUSEBUTTON_LEFT)
-    {
-      currentTracker_.reset(new RotateSceneTracker(viewportController_, pointerEvent));
-    }
-    else if (event.button == GUIADAPTER_MOUSEBUTTON_MIDDLE)
-    {
-      currentTracker_.reset(new PanSceneTracker(viewportController_, pointerEvent));
-    }
-    else if (event.button == GUIADAPTER_MOUSEBUTTON_RIGHT && compositor_.get() != NULL)
-    {
-      currentTracker_.reset(new ZoomSceneTracker(viewportController_, pointerEvent, compositor_->GetHeight()));
-    }
-    return true;
-  }
-  return false;
-}
-
-bool BasicScene2DInteractor::OnKeyboardEvent(const GuiAdapterKeyboardEvent& guiEvent)
-{
-  switch (guiEvent.sym[0])
-  {
-  case 's':
-  {
-    viewportController_->FitContent(compositor_->GetWidth(), compositor_->GetHeight());
-    return true;
-  };
-  }
-  return false;
-}
-
-bool BasicScene2DInteractor::OnWheelEvent(const GuiAdapterWheelEvent& guiEvent)
-{
-  return false;
-}
+/**
+ * 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 "Scene2DInteractor.h"
+
+#include "../../Framework/Scene2D/PanSceneTracker.h"
+#include "../../Framework/Scene2D/ZoomSceneTracker.h"
+#include "../../Framework/Scene2D/RotateSceneTracker.h"
+
+
+namespace OrthancStone
+{
+
+}
+
+using namespace OrthancStone;
+
+
+bool BasicScene2DInteractor::OnMouseEvent(const GuiAdapterMouseEvent& event, const PointerEvent& pointerEvent)
+{
+  if (currentTracker_.get() != NULL)
+  {
+    switch (event.type)
+    {
+    case GUIADAPTER_EVENT_MOUSEUP:
+    {
+      currentTracker_->PointerUp(pointerEvent);
+      if (!currentTracker_->IsAlive())
+      {
+        currentTracker_.reset();
+      }
+    };break;
+    case GUIADAPTER_EVENT_MOUSEMOVE:
+    {
+      currentTracker_->PointerMove(pointerEvent);
+    };break;
+    }
+    return true;
+  }
+  else
+  {
+    if (event.button == GUIADAPTER_MOUSEBUTTON_LEFT)
+    {
+      currentTracker_.reset(new RotateSceneTracker(viewportController_, pointerEvent));
+    }
+    else if (event.button == GUIADAPTER_MOUSEBUTTON_MIDDLE)
+    {
+      currentTracker_.reset(new PanSceneTracker(viewportController_, pointerEvent));
+    }
+    else if (event.button == GUIADAPTER_MOUSEBUTTON_RIGHT && compositor_.get() != NULL)
+    {
+      currentTracker_.reset(new ZoomSceneTracker(viewportController_, pointerEvent, compositor_->GetHeight()));
+    }
+    return true;
+  }
+  return false;
+}
+
+bool BasicScene2DInteractor::OnKeyboardEvent(const GuiAdapterKeyboardEvent& guiEvent)
+{
+  switch (guiEvent.sym[0])
+  {
+  case 's':
+  {
+    viewportController_->FitContent(compositor_->GetWidth(), compositor_->GetHeight());
+    return true;
+  };
+  }
+  return false;
+}
+
+bool BasicScene2DInteractor::OnWheelEvent(const GuiAdapterWheelEvent& guiEvent)
+{
+  return false;
+}
--- a/Deprecated/Samples/Qt/Scene2DInteractor.h	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/Qt/Scene2DInteractor.h	Fri Jun 12 07:19:31 2020 +0200
@@ -1,40 +1,40 @@
-/**
- * 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 "../../Applications/Generic/Scene2DInteractor.h"
-#include "../../Framework/Scene2DViewport/IFlexiblePointerTracker.h"
-
-
-class BasicScene2DInteractor : public OrthancStone::Scene2DInteractor
-{
-  boost::shared_ptr<OrthancStone::IFlexiblePointerTracker>  currentTracker_;
-public:
-  BasicScene2DInteractor(boost::shared_ptr<OrthancStone::ViewportController> viewportController) :
-    Scene2DInteractor(viewportController)
-  {}
-
-  virtual bool OnMouseEvent(const OrthancStone::GuiAdapterMouseEvent& event, const OrthancStone::PointerEvent& pointerEvent) override;
-  virtual bool OnKeyboardEvent(const OrthancStone::GuiAdapterKeyboardEvent& guiEvent);
-  virtual bool OnWheelEvent(const OrthancStone::GuiAdapterWheelEvent& guiEvent);
-};
-
+/**
+ * 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 "../../Applications/Generic/Scene2DInteractor.h"
+#include "../../Framework/Scene2DViewport/IFlexiblePointerTracker.h"
+
+
+class BasicScene2DInteractor : public OrthancStone::Scene2DInteractor
+{
+  boost::shared_ptr<OrthancStone::IFlexiblePointerTracker>  currentTracker_;
+public:
+  BasicScene2DInteractor(boost::shared_ptr<OrthancStone::ViewportController> viewportController) :
+    Scene2DInteractor(viewportController)
+  {}
+
+  virtual bool OnMouseEvent(const OrthancStone::GuiAdapterMouseEvent& event, const OrthancStone::PointerEvent& pointerEvent) override;
+  virtual bool OnKeyboardEvent(const OrthancStone::GuiAdapterKeyboardEvent& guiEvent);
+  virtual bool OnWheelEvent(const OrthancStone::GuiAdapterWheelEvent& guiEvent);
+};
+
--- a/Deprecated/Samples/Sdl/RadiographyEditor.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Deprecated/Samples/Sdl/RadiographyEditor.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,267 +1,267 @@
-/**
- * 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 "../Shared/RadiographyEditorApp.h"
-
-// From Stone
-#include "../../Framework/Oracle/SleepOracleCommand.h"
-#include "../../Framework/Oracle/ThreadedOracle.h"
-#include "../../Applications/Sdl/SdlOpenGLWindow.h"
-#include "../../Framework/Scene2D/OpenGLCompositor.h"
-#include "../../Framework/Scene2D/CairoCompositor.h"
-#include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
-#include "../../Framework/Scene2D/OpenGLCompositor.h"
-#include "../../Framework/StoneInitialization.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-#include <SDL.h>
-#include <stdio.h>
-
-using namespace OrthancStone;
-
-namespace OrthancStone
-{
-  class NativeApplicationContext : public IMessageEmitter
-  {
-  private:
-    boost::shared_mutex  mutex_;
-    MessageBroker        broker_;
-    IObservable          oracleObservable_;
-
-  public:
-    NativeApplicationContext() :
-      oracleObservable_(broker_)
-    {
-    }
-
-
-    virtual void EmitMessage(const IObserver& observer,
-                             const IMessage& message) ORTHANC_OVERRIDE
-    {
-      try
-      {
-        boost::unique_lock<boost::shared_mutex>  lock(mutex_);
-        oracleObservable_.EmitMessage(observer, message);
-      }
-      catch (Orthanc::OrthancException& e)
-      {
-        LOG(ERROR) << "Exception while emitting a message: " << e.What();
-      }
-    }
-
-
-    class ReaderLock : public boost::noncopyable
-    {
-    private:
-      NativeApplicationContext&                that_;
-      boost::shared_lock<boost::shared_mutex>  lock_;
-
-    public:
-      ReaderLock(NativeApplicationContext& that) :
-        that_(that),
-        lock_(that.mutex_)
-      {
-      }
-    };
-
-
-    class WriterLock : public boost::noncopyable
-    {
-    private:
-      NativeApplicationContext&                that_;
-      boost::unique_lock<boost::shared_mutex>  lock_;
-
-    public:
-      WriterLock(NativeApplicationContext& that) :
-        that_(that),
-        lock_(that.mutex_)
-      {
-      }
-
-      MessageBroker& GetBroker()
-      {
-        return that_.broker_;
-      }
-
-      IObservable& GetOracleObservable()
-      {
-        return that_.oracleObservable_;
-      }
-    };
-  };
-}
-
-class OpenGlSdlCompositorFactory : public ICompositorFactory
-{
-  OpenGL::IOpenGLContext& openGlContext_;
-
-public:
-  OpenGlSdlCompositorFactory(OpenGL::IOpenGLContext& openGlContext) :
-    openGlContext_(openGlContext)
-  {}
-
-  ICompositor* GetCompositor(const Scene2D& scene)
-  {
-
-    OpenGLCompositor* compositor = new OpenGLCompositor(openGlContext_, scene);
-    compositor->SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                         FONT_SIZE_0, Orthanc::Encoding_Latin1);
-    compositor->SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                         FONT_SIZE_1, Orthanc::Encoding_Latin1);
-    return compositor;
-  }
-};
-
-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);
-  }
-}
-
-
-/**
- * IMPORTANT: The full arguments to "main()" are needed for SDL on
- * Windows. Otherwise, one gets the linking error "undefined reference
- * to `SDL_main'". https://wiki.libsdl.org/FAQWindows
- **/
-int main(int argc, char* argv[])
-{
-  using namespace OrthancStone;
-
-  StoneInitialize();
-  Orthanc::Logging::EnableInfoLevel(true);
-  //  Orthanc::Logging::EnableTraceLevel(true);
-
-  try
-  {
-    OrthancStone::NativeApplicationContext context;
-    OrthancStone::NativeApplicationContext::WriterLock lock(context);
-    OrthancStone::ThreadedOracle oracle(context);
-
-    // False means we do NOT let Windows treat this as a legacy application
-    // that needs to be scaled
-    SdlOpenGLWindow window("Hello", 1024, 1024, false);
-
-    glEnable(GL_DEBUG_OUTPUT);
-    glDebugMessageCallback(OpenGLMessageCallback, 0);
-
-    std::unique_ptr<OpenGlSdlCompositorFactory> compositorFactory(new OpenGlSdlCompositorFactory(window));
-    boost::shared_ptr<RadiographyEditorApp> app(new RadiographyEditorApp(oracle, lock.GetOracleObservable(), compositorFactory.release()));
-    app->PrepareScene();
-    app->FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
-
-    bool stopApplication = false;
-
-    while (!stopApplication)
-    {
-      app->Refresh();
-
-      SDL_Event event;
-      while (!stopApplication && SDL_PollEvent(&event))
-      {
-        OrthancStone::KeyboardModifiers modifiers = OrthancStone::KeyboardModifiers_None;
-        if (event.key.keysym.mod & KMOD_CTRL)
-          modifiers = static_cast<OrthancStone::KeyboardModifiers>(static_cast<int>(modifiers) | static_cast<int>(OrthancStone::KeyboardModifiers_Control));
-        if (event.key.keysym.mod & KMOD_ALT)
-          modifiers = static_cast<OrthancStone::KeyboardModifiers>(static_cast<int>(modifiers) | static_cast<int>(OrthancStone::KeyboardModifiers_Alt));
-        if (event.key.keysym.mod & KMOD_SHIFT)
-          modifiers = static_cast<OrthancStone::KeyboardModifiers>(static_cast<int>(modifiers) | static_cast<int>(OrthancStone::KeyboardModifiers_Shift));
-
-        OrthancStone::MouseButton button;
-        if (event.button.button == SDL_BUTTON_LEFT)
-          button = OrthancStone::MouseButton_Left;
-        else if (event.button.button == SDL_BUTTON_MIDDLE)
-          button = OrthancStone::MouseButton_Middle;
-        else if (event.button.button == SDL_BUTTON_RIGHT)
-          button = OrthancStone::MouseButton_Right;
-
-        if (event.type == SDL_QUIT)
-        {
-          stopApplication = true;
-          break;
-        }
-        else if (event.type == SDL_WINDOWEVENT &&
-                 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
-        {
-          app->DisableTracker(); // was: tracker.reset(NULL);
-          app->UpdateSize();
-        }
-        else if (event.type == SDL_KEYDOWN &&
-                 event.key.repeat == 0 /* Ignore key bounce */)
-        {
-          switch (event.key.keysym.sym)
-          {
-          case SDLK_f:
-            window.GetWindow().ToggleMaximize();
-            break;
-
-          case SDLK_q:
-            stopApplication = true;
-            break;
-          default:
-          {
-            app->OnKeyPressed(event.key.keysym.sym, modifiers);
-           }
-          }
-        }
-        else if (event.type == SDL_MOUSEBUTTONDOWN)
-        {
-          app->OnMouseDown(event.button.x, event.button.y, modifiers, button);
-        }
-        else if (event.type == SDL_MOUSEMOTION)
-        {
-          app->OnMouseMove(event.button.x, event.button.y, modifiers);
-        }
-        else if (event.type == SDL_MOUSEBUTTONUP)
-        {
-          app->OnMouseUp(event.button.x, event.button.y, modifiers, button);
-        }
-      }
-      SDL_Delay(1);
-    }
-  }
-  catch (Orthanc::OrthancException& e)
-  {
-    LOG(ERROR) << "EXCEPTION: " << e.What();
-  }
-
-  StoneFinalize();
-
-  return 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 "../Shared/RadiographyEditorApp.h"
+
+// From Stone
+#include "../../Framework/Oracle/SleepOracleCommand.h"
+#include "../../Framework/Oracle/ThreadedOracle.h"
+#include "../../Applications/Sdl/SdlOpenGLWindow.h"
+#include "../../Framework/Scene2D/OpenGLCompositor.h"
+#include "../../Framework/Scene2D/CairoCompositor.h"
+#include "../../Framework/Scene2D/ColorTextureSceneLayer.h"
+#include "../../Framework/Scene2D/OpenGLCompositor.h"
+#include "../../Framework/StoneInitialization.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <SDL.h>
+#include <stdio.h>
+
+using namespace OrthancStone;
+
+namespace OrthancStone
+{
+  class NativeApplicationContext : public IMessageEmitter
+  {
+  private:
+    boost::shared_mutex  mutex_;
+    MessageBroker        broker_;
+    IObservable          oracleObservable_;
+
+  public:
+    NativeApplicationContext() :
+      oracleObservable_(broker_)
+    {
+    }
+
+
+    virtual void EmitMessage(const IObserver& observer,
+                             const IMessage& message) ORTHANC_OVERRIDE
+    {
+      try
+      {
+        boost::unique_lock<boost::shared_mutex>  lock(mutex_);
+        oracleObservable_.EmitMessage(observer, message);
+      }
+      catch (Orthanc::OrthancException& e)
+      {
+        LOG(ERROR) << "Exception while emitting a message: " << e.What();
+      }
+    }
+
+
+    class ReaderLock : public boost::noncopyable
+    {
+    private:
+      NativeApplicationContext&                that_;
+      boost::shared_lock<boost::shared_mutex>  lock_;
+
+    public:
+      ReaderLock(NativeApplicationContext& that) :
+        that_(that),
+        lock_(that.mutex_)
+      {
+      }
+    };
+
+
+    class WriterLock : public boost::noncopyable
+    {
+    private:
+      NativeApplicationContext&                that_;
+      boost::unique_lock<boost::shared_mutex>  lock_;
+
+    public:
+      WriterLock(NativeApplicationContext& that) :
+        that_(that),
+        lock_(that.mutex_)
+      {
+      }
+
+      MessageBroker& GetBroker()
+      {
+        return that_.broker_;
+      }
+
+      IObservable& GetOracleObservable()
+      {
+        return that_.oracleObservable_;
+      }
+    };
+  };
+}
+
+class OpenGlSdlCompositorFactory : public ICompositorFactory
+{
+  OpenGL::IOpenGLContext& openGlContext_;
+
+public:
+  OpenGlSdlCompositorFactory(OpenGL::IOpenGLContext& openGlContext) :
+    openGlContext_(openGlContext)
+  {}
+
+  ICompositor* GetCompositor(const Scene2D& scene)
+  {
+
+    OpenGLCompositor* compositor = new OpenGLCompositor(openGlContext_, scene);
+    compositor->SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
+                         FONT_SIZE_0, Orthanc::Encoding_Latin1);
+    compositor->SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
+                         FONT_SIZE_1, Orthanc::Encoding_Latin1);
+    return compositor;
+  }
+};
+
+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);
+  }
+}
+
+
+/**
+ * IMPORTANT: The full arguments to "main()" are needed for SDL on
+ * Windows. Otherwise, one gets the linking error "undefined reference
+ * to `SDL_main'". https://wiki.libsdl.org/FAQWindows
+ **/
+int main(int argc, char* argv[])
+{
+  using namespace OrthancStone;
+
+  StoneInitialize();
+  Orthanc::Logging::EnableInfoLevel(true);
+  //  Orthanc::Logging::EnableTraceLevel(true);
+
+  try
+  {
+    OrthancStone::NativeApplicationContext context;
+    OrthancStone::NativeApplicationContext::WriterLock lock(context);
+    OrthancStone::ThreadedOracle oracle(context);
+
+    // False means we do NOT let Windows treat this as a legacy application
+    // that needs to be scaled
+    SdlOpenGLWindow window("Hello", 1024, 1024, false);
+
+    glEnable(GL_DEBUG_OUTPUT);
+    glDebugMessageCallback(OpenGLMessageCallback, 0);
+
+    std::unique_ptr<OpenGlSdlCompositorFactory> compositorFactory(new OpenGlSdlCompositorFactory(window));
+    boost::shared_ptr<RadiographyEditorApp> app(new RadiographyEditorApp(oracle, lock.GetOracleObservable(), compositorFactory.release()));
+    app->PrepareScene();
+    app->FitContent(window.GetCanvasWidth(), window.GetCanvasHeight());
+
+    bool stopApplication = false;
+
+    while (!stopApplication)
+    {
+      app->Refresh();
+
+      SDL_Event event;
+      while (!stopApplication && SDL_PollEvent(&event))
+      {
+        OrthancStone::KeyboardModifiers modifiers = OrthancStone::KeyboardModifiers_None;
+        if (event.key.keysym.mod & KMOD_CTRL)
+          modifiers = static_cast<OrthancStone::KeyboardModifiers>(static_cast<int>(modifiers) | static_cast<int>(OrthancStone::KeyboardModifiers_Control));
+        if (event.key.keysym.mod & KMOD_ALT)
+          modifiers = static_cast<OrthancStone::KeyboardModifiers>(static_cast<int>(modifiers) | static_cast<int>(OrthancStone::KeyboardModifiers_Alt));
+        if (event.key.keysym.mod & KMOD_SHIFT)
+          modifiers = static_cast<OrthancStone::KeyboardModifiers>(static_cast<int>(modifiers) | static_cast<int>(OrthancStone::KeyboardModifiers_Shift));
+
+        OrthancStone::MouseButton button;
+        if (event.button.button == SDL_BUTTON_LEFT)
+          button = OrthancStone::MouseButton_Left;
+        else if (event.button.button == SDL_BUTTON_MIDDLE)
+          button = OrthancStone::MouseButton_Middle;
+        else if (event.button.button == SDL_BUTTON_RIGHT)
+          button = OrthancStone::MouseButton_Right;
+
+        if (event.type == SDL_QUIT)
+        {
+          stopApplication = true;
+          break;
+        }
+        else if (event.type == SDL_WINDOWEVENT &&
+                 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
+        {
+          app->DisableTracker(); // was: tracker.reset(NULL);
+          app->UpdateSize();
+        }
+        else if (event.type == SDL_KEYDOWN &&
+                 event.key.repeat == 0 /* Ignore key bounce */)
+        {
+          switch (event.key.keysym.sym)
+          {
+          case SDLK_f:
+            window.GetWindow().ToggleMaximize();
+            break;
+
+          case SDLK_q:
+            stopApplication = true;
+            break;
+          default:
+          {
+            app->OnKeyPressed(event.key.keysym.sym, modifiers);
+           }
+          }
+        }
+        else if (event.type == SDL_MOUSEBUTTONDOWN)
+        {
+          app->OnMouseDown(event.button.x, event.button.y, modifiers, button);
+        }
+        else if (event.type == SDL_MOUSEMOTION)
+        {
+          app->OnMouseMove(event.button.x, event.button.y, modifiers);
+        }
+        else if (event.type == SDL_MOUSEBUTTONUP)
+        {
+          app->OnMouseUp(event.button.x, event.button.y, modifiers, button);
+        }
+      }
+      SDL_Delay(1);
+    }
+  }
+  catch (Orthanc::OrthancException& e)
+  {
+    LOG(ERROR) << "EXCEPTION: " << e.What();
+  }
+
+  StoneFinalize();
+
+  return 0;
+}
+
+
--- a/Framework/Deprecated/Loaders/DicomStructureSetLoader2.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Framework/Deprecated/Loaders/DicomStructureSetLoader2.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -28,7 +28,7 @@
 
 namespace Deprecated
 {
-
+
   DicomStructureSetLoader2::DicomStructureSetLoader2(
     DicomStructureSet2& structureSet
     , IOracle& oracle
@@ -45,10 +45,10 @@
     oracleObservable.RegisterObserverCallback(
       new Callable<DicomStructureSetLoader2, OrthancRestApiCommand::SuccessMessage>
       (*this, &DicomStructureSetLoader2::HandleSuccessMessage));
-
+
     oracleObservable.RegisterObserverCallback(
       new Callable<DicomStructureSetLoader2, OracleCommandExceptionMessage>
-      (*this, &DicomStructureSetLoader2::HandleExceptionMessage));
+      (*this, &DicomStructureSetLoader2::HandleExceptionMessage));
   }
 
   DicomStructureSetLoader2::~DicomStructureSetLoader2()
@@ -99,27 +99,27 @@
   {
     return structuresReady_;
   }
-
-  /*
-
+
+  /*
+
     void LoaderStateMachine::HandleExceptionMessage(const OracleCommandExceptionMessage& message)
     {
       LOG(ERROR) << "LoaderStateMachine::HandleExceptionMessage: error in the state machine, stopping all processing";
       LOG(ERROR) << "Error: " << message.GetException().What() << " Details: " <<
         message.GetException().GetDetails();
         Clear();
-    }
-
+    }
+
     LoaderStateMachine::~LoaderStateMachine()
     {
       Clear();
     }
-
-
-  */
-
-}
-
+
+
+  */
+
+}
+
 #endif 
 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2
 
--- a/Framework/Toolbox/DicomStructurePolygon2.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Framework/Toolbox/DicomStructurePolygon2.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -185,10 +185,10 @@
             // alpha = (v2-planeV)/(v2-v1)
             // because the following two triangles are similar
             // [ (planeY,x)  , (y2,x2), (planeY,x2) ] or
-            // [ (planeX,y)  , (x2,y2), (planeX,y2) ]
+            // [ (planeX,y)  , (x2,y2), (planeX,y2) ]
             // and
             // [ (y1    ,x1) , (y2,x2), (y1    ,x2) ] or
-            // [ (x1    ,y1) , (x2,y2), (x1    ,y2) ]
+            // [ (x1    ,y1) , (x2,y2), (x1    ,y2) ]
 
             /*
               void CoordinateSystem3D::ProjectPoint(double& offsetX,
@@ -218,7 +218,7 @@
 
               // we consider that the x axis is always parallel to the polygons
               // TODO: is this hypothesis safe??????
-              uIntersections.insert(std::lower_bound(uIntersections.begin(), uIntersections.end(), xi), xi);
+              uIntersections.insert(std::lower_bound(uIntersections.begin(), uIntersections.end(), xi), xi);
             }
           }
         }
--- a/Framework/Toolbox/DicomStructureSetUtils.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Framework/Toolbox/DicomStructureSetUtils.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -76,19 +76,19 @@
 
     /*
 
-      compute list of segments :
-
-      numberOfRectsFromHereOn = 0
-      possibleNext = {in_k,in_kplus1}
-
-      for all boundaries:
-        - we create a vertical segment and we push it
-        - if boundary is a start, numberOfRectsFromHereOn += 1.
-          - if we switch from 0 to 1, we start a segment
-          - if we switch from 1 to 2, we end the current segment and we record it
-        - if boundary is an end, numberOfRectsFromHereOn -= 1.
-          - if we switch from 1 to 0, we end the current segment and we record it
-          - if we switch from 2 to 1, we start a segment
+      compute list of segments :
+
+      numberOfRectsFromHereOn = 0
+      possibleNext = {in_k,in_kplus1}
+
+      for all boundaries:
+        - we create a vertical segment and we push it
+        - if boundary is a start, numberOfRectsFromHereOn += 1.
+          - if we switch from 0 to 1, we start a segment
+          - if we switch from 1 to 2, we end the current segment and we record it
+        - if boundary is an end, numberOfRectsFromHereOn -= 1.
+          - if we switch from 1 to 0, we end the current segment and we record it
+          - if we switch from 2 to 1, we start a segment
     */
 
     // static
@@ -104,11 +104,11 @@
           const RtStructRectangleInSlab& rect = slab[iRect];
           {
             std::pair<double, RectangleBoundaryKind> boundary(rect.xmin, RectangleBoundaryKind_Start);
-            boundaries.insert(std::lower_bound(boundaries.begin(), boundaries.end(), boundary), boundary);
+            boundaries.insert(std::lower_bound(boundaries.begin(), boundaries.end(), boundary), boundary);
           }
           {
             std::pair<double, RectangleBoundaryKind> boundary(rect.xmax, RectangleBoundaryKind_End);
-            boundaries.insert(std::lower_bound(boundaries.begin(), boundaries.end(), boundary), boundary);
+            boundaries.insert(std::lower_bound(boundaries.begin(), boundaries.end(), boundary), boundary);
           }
         }
       }
--- a/Framework/Toolbox/TextRenderer.cpp	Fri Jun 12 07:18:07 2020 +0200
+++ b/Framework/Toolbox/TextRenderer.cpp	Fri Jun 12 07:19:31 2020 +0200
@@ -1,136 +1,136 @@
-/**
- * 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 "TextRenderer.h"
-
-#include "../Scene2D/CairoCompositor.h"
-#include "../Scene2D/ColorTextureSceneLayer.h"
-#include "../Scene2D/FloatTextureSceneLayer.h"
-#include "../Scene2D/TextSceneLayer.h"
-#include "../Fonts/GlyphBitmapAlphabet.h"
-#include "../Fonts/FontRenderer.h"
-
-#include <Images/Image.h>
-#include <Images/ImageProcessing.h>
-#include <Images/PngWriter.h>
-#include <Toolbox.h>
-
-namespace OrthancStone
-{
-  Orthanc::ImageAccessor* TextRenderer::Render(Orthanc::EmbeddedResources::FileResourceId font,
-                                               unsigned int fontSize,
-                                               const std::string& utf8String
-                                               )
-  {
-    FontRenderer renderer;
-    renderer.LoadFont(font, fontSize);
-
-    // add each char to be rendered to the alphabet
-    std::unique_ptr<GlyphBitmapAlphabet> alphabet(new GlyphBitmapAlphabet);
-
-    size_t posInString = 0;
-    uint32_t unicode;
-    size_t utf8CharLength;
-
-    while (posInString < utf8String.size())
-    {
-      Orthanc::Toolbox::Utf8ToUnicodeCharacter(unicode, utf8CharLength, utf8String, posInString);
-      alphabet->AddUnicodeCharacter(renderer, unicode);
-      posInString += utf8CharLength;
-    }
-
-
-    std::unique_ptr<Orthanc::ImageAccessor> renderedText(alphabet->RenderText(utf8String));
-
-    // add a blank line on top of the text (to improve bilinear filtering of the topmost line)
-    std::unique_ptr<Orthanc::Image> renderedTextExtended(new Orthanc::Image(renderedText->GetFormat(), renderedText->GetWidth(), renderedText->GetHeight() + 1, true));
-
-    Orthanc::ImageAccessor textRegion;
-    Orthanc::ImageAccessor firstLineRegion;
-
-    renderedTextExtended->GetRegion(firstLineRegion, 0, 0, renderedText->GetWidth(), 1);
-    Orthanc::ImageProcessing::Set(firstLineRegion, 0);
-
-    renderedTextExtended->GetRegion(textRegion, 0, 1, renderedText->GetWidth(), renderedText->GetHeight());
-    Orthanc::ImageProcessing::Copy(textRegion, *renderedText);
-
-    return renderedTextExtended.release();
-  }
-
-
-  Orthanc::ImageAccessor* TextRenderer::RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
-                                                        unsigned int fontSize,
-                                                        const std::string& utf8String,
-                                                        uint8_t foreground)
-  {
-    std::unique_ptr<Orthanc::ImageAccessor> renderedText8(Render(resource, fontSize, utf8String));
-    std::unique_ptr<Orthanc::Image> target(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, renderedText8->GetWidth(), renderedText8->GetHeight(), true));
-
-    Orthanc::ImageProcessing::Set(*target, foreground, foreground, foreground, *renderedText8);
-    return target.release();
-  }
-
-
-  // currently disabled because the background is actually not transparent once we use the Cairo Compositor !
-  //
-  //  // renders text in color + a border with alpha in a RGBA32 image
-  //  Orthanc::ImageAccessor* TextRenderer::RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
-  //                                                        unsigned int fontSize,
-  //                                                        const std::string& utf8String,
-  //                                                        uint8_t foreground,
-  //                                                        uint8_t borderColor)
-  //  {
-  //    std::unique_ptr<Orthanc::ImageAccessor> renderedBorderAlpha(RenderWithAlpha(resource, fontSize, utf8String, borderColor));
-  //    std::unique_ptr<Orthanc::ImageAccessor> renderedTextAlpha(RenderWithAlpha(resource, fontSize, utf8String, foreground));
-
-  //    unsigned int textWidth = renderedBorderAlpha->GetWidth();
-  //    unsigned int textHeight = renderedBorderAlpha->GetHeight();
-
-  //    Scene2D targetScene;
-  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerLeft(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerRight(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerTop(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerBottom(new ColorTextureSceneLayer(*renderedBorderAlpha));
-  //    std::unique_ptr<ColorTextureSceneLayer> textLayerCenter(new ColorTextureSceneLayer(*renderedTextAlpha));
-
-  //    borderLayerLeft->SetOrigin(0, 1);
-  //    borderLayerRight->SetOrigin(2, 1);
-  //    borderLayerTop->SetOrigin(1, 0);
-  //    borderLayerBottom->SetOrigin(1, 2);
-  //    textLayerCenter->SetOrigin(1, 1);
-  //    targetScene.SetLayer(1, borderLayerLeft.release());
-  //    targetScene.SetLayer(2, borderLayerRight.release());
-  //    targetScene.SetLayer(3, borderLayerTop.release());
-  //    targetScene.SetLayer(4, borderLayerBottom.release());
-  //    targetScene.SetLayer(5, textLayerCenter.release());
-
-  //    targetScene.FitContent(textWidth + 2, textHeight + 2);
-  //    CairoCompositor compositor(targetScene, textWidth + 2, textHeight + 2);
-  //    compositor.Refresh();
-
-  //    Orthanc::ImageAccessor canvas;
-  //    compositor.GetCanvas().GetReadOnlyAccessor(canvas);
-
-  //    std::unique_ptr<Orthanc::Image> output(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, canvas.GetWidth(), canvas.GetHeight(), false));
-  //    Orthanc::ImageProcessing::Convert(*output, canvas);
-  //    return output.release();
-  //  }
-}
+/**
+ * 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 "TextRenderer.h"
+
+#include "../Scene2D/CairoCompositor.h"
+#include "../Scene2D/ColorTextureSceneLayer.h"
+#include "../Scene2D/FloatTextureSceneLayer.h"
+#include "../Scene2D/TextSceneLayer.h"
+#include "../Fonts/GlyphBitmapAlphabet.h"
+#include "../Fonts/FontRenderer.h"
+
+#include <Images/Image.h>
+#include <Images/ImageProcessing.h>
+#include <Images/PngWriter.h>
+#include <Toolbox.h>
+
+namespace OrthancStone
+{
+  Orthanc::ImageAccessor* TextRenderer::Render(Orthanc::EmbeddedResources::FileResourceId font,
+                                               unsigned int fontSize,
+                                               const std::string& utf8String
+                                               )
+  {
+    FontRenderer renderer;
+    renderer.LoadFont(font, fontSize);
+
+    // add each char to be rendered to the alphabet
+    std::unique_ptr<GlyphBitmapAlphabet> alphabet(new GlyphBitmapAlphabet);
+
+    size_t posInString = 0;
+    uint32_t unicode;
+    size_t utf8CharLength;
+
+    while (posInString < utf8String.size())
+    {
+      Orthanc::Toolbox::Utf8ToUnicodeCharacter(unicode, utf8CharLength, utf8String, posInString);
+      alphabet->AddUnicodeCharacter(renderer, unicode);
+      posInString += utf8CharLength;
+    }
+
+
+    std::unique_ptr<Orthanc::ImageAccessor> renderedText(alphabet->RenderText(utf8String));
+
+    // add a blank line on top of the text (to improve bilinear filtering of the topmost line)
+    std::unique_ptr<Orthanc::Image> renderedTextExtended(new Orthanc::Image(renderedText->GetFormat(), renderedText->GetWidth(), renderedText->GetHeight() + 1, true));
+
+    Orthanc::ImageAccessor textRegion;
+    Orthanc::ImageAccessor firstLineRegion;
+
+    renderedTextExtended->GetRegion(firstLineRegion, 0, 0, renderedText->GetWidth(), 1);
+    Orthanc::ImageProcessing::Set(firstLineRegion, 0);
+
+    renderedTextExtended->GetRegion(textRegion, 0, 1, renderedText->GetWidth(), renderedText->GetHeight());
+    Orthanc::ImageProcessing::Copy(textRegion, *renderedText);
+
+    return renderedTextExtended.release();
+  }
+
+
+  Orthanc::ImageAccessor* TextRenderer::RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
+                                                        unsigned int fontSize,
+                                                        const std::string& utf8String,
+                                                        uint8_t foreground)
+  {
+    std::unique_ptr<Orthanc::ImageAccessor> renderedText8(Render(resource, fontSize, utf8String));
+    std::unique_ptr<Orthanc::Image> target(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, renderedText8->GetWidth(), renderedText8->GetHeight(), true));
+
+    Orthanc::ImageProcessing::Set(*target, foreground, foreground, foreground, *renderedText8);
+    return target.release();
+  }
+
+
+  // currently disabled because the background is actually not transparent once we use the Cairo Compositor !
+  //
+  //  // renders text in color + a border with alpha in a RGBA32 image
+  //  Orthanc::ImageAccessor* TextRenderer::RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
+  //                                                        unsigned int fontSize,
+  //                                                        const std::string& utf8String,
+  //                                                        uint8_t foreground,
+  //                                                        uint8_t borderColor)
+  //  {
+  //    std::unique_ptr<Orthanc::ImageAccessor> renderedBorderAlpha(RenderWithAlpha(resource, fontSize, utf8String, borderColor));
+  //    std::unique_ptr<Orthanc::ImageAccessor> renderedTextAlpha(RenderWithAlpha(resource, fontSize, utf8String, foreground));
+
+  //    unsigned int textWidth = renderedBorderAlpha->GetWidth();
+  //    unsigned int textHeight = renderedBorderAlpha->GetHeight();
+
+  //    Scene2D targetScene;
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerLeft(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerRight(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerTop(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> borderLayerBottom(new ColorTextureSceneLayer(*renderedBorderAlpha));
+  //    std::unique_ptr<ColorTextureSceneLayer> textLayerCenter(new ColorTextureSceneLayer(*renderedTextAlpha));
+
+  //    borderLayerLeft->SetOrigin(0, 1);
+  //    borderLayerRight->SetOrigin(2, 1);
+  //    borderLayerTop->SetOrigin(1, 0);
+  //    borderLayerBottom->SetOrigin(1, 2);
+  //    textLayerCenter->SetOrigin(1, 1);
+  //    targetScene.SetLayer(1, borderLayerLeft.release());
+  //    targetScene.SetLayer(2, borderLayerRight.release());
+  //    targetScene.SetLayer(3, borderLayerTop.release());
+  //    targetScene.SetLayer(4, borderLayerBottom.release());
+  //    targetScene.SetLayer(5, textLayerCenter.release());
+
+  //    targetScene.FitContent(textWidth + 2, textHeight + 2);
+  //    CairoCompositor compositor(targetScene, textWidth + 2, textHeight + 2);
+  //    compositor.Refresh();
+
+  //    Orthanc::ImageAccessor canvas;
+  //    compositor.GetCanvas().GetReadOnlyAccessor(canvas);
+
+  //    std::unique_ptr<Orthanc::Image> output(new Orthanc::Image(Orthanc::PixelFormat_RGBA32, canvas.GetWidth(), canvas.GetHeight(), false));
+  //    Orthanc::ImageProcessing::Convert(*output, canvas);
+  //    return output.release();
+  //  }
+}
--- a/Framework/Toolbox/TextRenderer.h	Fri Jun 12 07:18:07 2020 +0200
+++ b/Framework/Toolbox/TextRenderer.h	Fri Jun 12 07:19:31 2020 +0200
@@ -1,53 +1,53 @@
-/**
- * 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 <Images/Image.h>
-#include <EmbeddedResources.h>
-
-namespace OrthancStone
-{
-  // Helpers methods to render text in bitmaps.
-  // Compared to the GlyphBitmapAlphabet::RenderText, these methods do not need a
-  // code page.
-  class TextRenderer : public boost::noncopyable
-  {
-  public:
-    // simply renders text in GrayScale8 with a black background and a white text
-    static Orthanc::ImageAccessor* Render(Orthanc::EmbeddedResources::FileResourceId resource,
-                                          unsigned int fontSize,
-                                          const std::string& utf8String);
-
-    // renders text in "color" with alpha in a RGBA32 image
-    static Orthanc::ImageAccessor* RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
-                                                   unsigned int fontSize,
-                                                   const std::string& utf8String,
-                                                   uint8_t foreground);
-
-    //    // renders text in color + a border with alpha in a RGBA32 image
-    //    static Orthanc::ImageAccessor* RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
-    //                                                   unsigned int fontSize,
-    //                                                   const std::string& utf8String,
-    //                                                   uint8_t foreground,
-    //                                                   uint8_t borderColor);
-  };
-}
+/**
+ * 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 <Images/Image.h>
+#include <EmbeddedResources.h>
+
+namespace OrthancStone
+{
+  // Helpers methods to render text in bitmaps.
+  // Compared to the GlyphBitmapAlphabet::RenderText, these methods do not need a
+  // code page.
+  class TextRenderer : public boost::noncopyable
+  {
+  public:
+    // simply renders text in GrayScale8 with a black background and a white text
+    static Orthanc::ImageAccessor* Render(Orthanc::EmbeddedResources::FileResourceId resource,
+                                          unsigned int fontSize,
+                                          const std::string& utf8String);
+
+    // renders text in "color" with alpha in a RGBA32 image
+    static Orthanc::ImageAccessor* RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
+                                                   unsigned int fontSize,
+                                                   const std::string& utf8String,
+                                                   uint8_t foreground);
+
+    //    // renders text in color + a border with alpha in a RGBA32 image
+    //    static Orthanc::ImageAccessor* RenderWithAlpha(Orthanc::EmbeddedResources::FileResourceId resource,
+    //                                                   unsigned int fontSize,
+    //                                                   const std::string& utf8String,
+    //                                                   uint8_t foreground,
+    //                                                   uint8_t borderColor);
+  };
+}