changeset 1399:ff8d2e46ac63

moved Applications into Deprecated
author Alain Mazy <alain@mazy.be>
date Wed, 29 Apr 2020 20:44:31 +0200
parents c5403d52078c
children 419d0320c344
files Applications/Commands/BaseCommands.yml Applications/Generic/GuiAdapter.cpp Applications/Generic/GuiAdapter.h Applications/Generic/NativeStoneApplicationContext.cpp Applications/Generic/NativeStoneApplicationContext.h Applications/Generic/NativeStoneApplicationRunner.cpp Applications/Generic/NativeStoneApplicationRunner.h Applications/Generic/Scene2DInteractor.h Applications/IStoneApplication.h Applications/Qt/QCairoWidget.cpp Applications/Qt/QCairoWidget.h Applications/Qt/QStoneMainWindow.cpp Applications/Qt/QStoneMainWindow.h Applications/Qt/QtStoneApplicationRunner.cpp Applications/Qt/QtStoneApplicationRunner.h Applications/Samples/Deprecated/BasicPetCtFusionApplication.h Applications/Samples/Deprecated/CMakeLists.txt Applications/Samples/Deprecated/CMakeLists.txt.old Applications/Samples/Deprecated/EmptyApplication.h Applications/Samples/Deprecated/LayoutPetCtFusionApplication.h Applications/Samples/Deprecated/Qt/SampleMainWindow.cpp Applications/Samples/Deprecated/Qt/SampleMainWindow.h Applications/Samples/Deprecated/Qt/SampleMainWindow.ui Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.cpp Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.h Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.ui Applications/Samples/Deprecated/Qt/SampleQtApplicationRunner.h Applications/Samples/Deprecated/SampleApplicationBase.h Applications/Samples/Deprecated/SampleInteractor.h Applications/Samples/Deprecated/SampleList.h Applications/Samples/Deprecated/SampleMainNative.cpp Applications/Samples/Deprecated/SampleMainWasm.cpp Applications/Samples/Deprecated/Samples-status.md Applications/Samples/Deprecated/SimpleViewer/AppStatus.h Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.cpp Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.h Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.cpp Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.h Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui Applications/Samples/Deprecated/SimpleViewer/Qt/mainQt.cpp Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.cpp Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.h Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.cpp Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.h Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.h Applications/Samples/Deprecated/SimpleViewer/Wasm/mainWasm.cpp Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.html Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.ts Applications/Samples/Deprecated/SimpleViewer/Wasm/styles.css Applications/Samples/Deprecated/SimpleViewer/Wasm/tsconfig-simple-viewer.json Applications/Samples/Deprecated/SimpleViewerApplicationSingleFile.h Applications/Samples/Deprecated/SingleFrameApplication.h Applications/Samples/Deprecated/SingleFrameEditorApplication.h Applications/Samples/Deprecated/SingleVolumeApplication.h Applications/Samples/Deprecated/StoneSampleCommands.yml Applications/Samples/Deprecated/StoneSampleCommands_generate.py Applications/Samples/Deprecated/StoneSampleCommands_generated.hpp Applications/Samples/Deprecated/StoneSampleCommands_generated.ts Applications/Samples/Deprecated/SynchronizedSeriesApplication.h Applications/Samples/Deprecated/TestPatternApplication.h Applications/Samples/Deprecated/Web/index.html Applications/Samples/Deprecated/Web/samples-styles.css Applications/Samples/Deprecated/Web/simple-viewer-single-file.html Applications/Samples/Deprecated/Web/simple-viewer-single-file.ts Applications/Samples/Deprecated/Web/simple-viewer-single-file.tsconfig.json Applications/Samples/Deprecated/Web/single-frame-editor.html Applications/Samples/Deprecated/Web/single-frame-editor.ts Applications/Samples/Deprecated/Web/single-frame-editor.tsconfig.json Applications/Samples/Deprecated/Web/single-frame.html Applications/Samples/Deprecated/Web/single-frame.ts Applications/Samples/Deprecated/Web/single-frame.tsconfig.json Applications/Samples/Deprecated/Web/tsconfig-samples.json Applications/Samples/Deprecated/build-wasm.sh Applications/Samples/Deprecated/build-wasm.sh.old Applications/Samples/Deprecated/build-web-ext.sh Applications/Samples/Deprecated/build-web.sh Applications/Samples/Deprecated/get-requirements-windows.ps1 Applications/Samples/Deprecated/nginx.local.conf Applications/Samples/Deprecated/package-lock.json Applications/Samples/Deprecated/rt-viewer-demo/CMakeLists.txt Applications/Samples/Deprecated/rt-viewer-demo/build-sdl-msvc15.ps1 Applications/Samples/Deprecated/rt-viewer-demo/build-wasm.sh Applications/Samples/Deprecated/rt-viewer-demo/build-web.sh Applications/Samples/Deprecated/rt-viewer-demo/index.html Applications/Samples/Deprecated/rt-viewer-demo/main.cpp Applications/Samples/Deprecated/rt-viewer-demo/nginx.local.conf Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.html Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.ts Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.tsconfig.json Applications/Samples/Deprecated/rt-viewer-demo/samples-styles.css Applications/Samples/Deprecated/rt-viewer-demo/start-serving-files.sh Applications/Samples/Deprecated/rt-viewer-demo/stop-serving-files.sh Applications/Samples/Deprecated/rt-viewer-demo/tsconfig-samples.json Applications/Samples/Deprecated/tsconfig-stone.json Applications/Sdl/SdlCairoSurface.cpp Applications/Sdl/SdlCairoSurface.h Applications/Sdl/SdlEngine.cpp Applications/Sdl/SdlEngine.h Applications/Sdl/SdlOrthancSurface.cpp Applications/Sdl/SdlOrthancSurface.h Applications/Sdl/SdlStoneApplicationRunner.cpp Applications/Sdl/SdlStoneApplicationRunner.h Applications/StoneApplicationContext.cpp Applications/StoneApplicationContext.h Applications/Wasm/StartupParametersBuilder.cpp Applications/Wasm/StartupParametersBuilder.h Deprecated/Applications/Commands/BaseCommands.yml Deprecated/Applications/Generic/GuiAdapter.cpp Deprecated/Applications/Generic/GuiAdapter.h Deprecated/Applications/Generic/NativeStoneApplicationContext.cpp Deprecated/Applications/Generic/NativeStoneApplicationContext.h Deprecated/Applications/Generic/NativeStoneApplicationRunner.cpp Deprecated/Applications/Generic/NativeStoneApplicationRunner.h Deprecated/Applications/Generic/Scene2DInteractor.h Deprecated/Applications/IStoneApplication.h Deprecated/Applications/Qt/QCairoWidget.cpp Deprecated/Applications/Qt/QCairoWidget.h Deprecated/Applications/Qt/QStoneMainWindow.cpp Deprecated/Applications/Qt/QStoneMainWindow.h Deprecated/Applications/Qt/QtStoneApplicationRunner.cpp Deprecated/Applications/Qt/QtStoneApplicationRunner.h Deprecated/Applications/Samples/Deprecated/BasicPetCtFusionApplication.h Deprecated/Applications/Samples/Deprecated/CMakeLists.txt Deprecated/Applications/Samples/Deprecated/CMakeLists.txt.old Deprecated/Applications/Samples/Deprecated/EmptyApplication.h Deprecated/Applications/Samples/Deprecated/LayoutPetCtFusionApplication.h Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindow.cpp Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindow.h Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindow.ui Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.cpp Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.h Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.ui Deprecated/Applications/Samples/Deprecated/Qt/SampleQtApplicationRunner.h Deprecated/Applications/Samples/Deprecated/SampleApplicationBase.h Deprecated/Applications/Samples/Deprecated/SampleInteractor.h Deprecated/Applications/Samples/Deprecated/SampleList.h Deprecated/Applications/Samples/Deprecated/SampleMainNative.cpp Deprecated/Applications/Samples/Deprecated/SampleMainWasm.cpp Deprecated/Applications/Samples/Deprecated/Samples-status.md Deprecated/Applications/Samples/Deprecated/SimpleViewer/AppStatus.h Deprecated/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.h Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.h Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/mainQt.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.h Deprecated/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.h Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.h Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/mainWasm.cpp Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.html Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.ts Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/styles.css Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/tsconfig-simple-viewer.json Deprecated/Applications/Samples/Deprecated/SimpleViewerApplicationSingleFile.h Deprecated/Applications/Samples/Deprecated/SingleFrameApplication.h Deprecated/Applications/Samples/Deprecated/SingleFrameEditorApplication.h Deprecated/Applications/Samples/Deprecated/SingleVolumeApplication.h Deprecated/Applications/Samples/Deprecated/StoneSampleCommands.yml Deprecated/Applications/Samples/Deprecated/StoneSampleCommands_generate.py Deprecated/Applications/Samples/Deprecated/StoneSampleCommands_generated.hpp Deprecated/Applications/Samples/Deprecated/StoneSampleCommands_generated.ts Deprecated/Applications/Samples/Deprecated/SynchronizedSeriesApplication.h Deprecated/Applications/Samples/Deprecated/TestPatternApplication.h Deprecated/Applications/Samples/Deprecated/Web/index.html Deprecated/Applications/Samples/Deprecated/Web/samples-styles.css Deprecated/Applications/Samples/Deprecated/Web/simple-viewer-single-file.html Deprecated/Applications/Samples/Deprecated/Web/simple-viewer-single-file.ts Deprecated/Applications/Samples/Deprecated/Web/simple-viewer-single-file.tsconfig.json Deprecated/Applications/Samples/Deprecated/Web/single-frame-editor.html Deprecated/Applications/Samples/Deprecated/Web/single-frame-editor.ts Deprecated/Applications/Samples/Deprecated/Web/single-frame-editor.tsconfig.json Deprecated/Applications/Samples/Deprecated/Web/single-frame.html Deprecated/Applications/Samples/Deprecated/Web/single-frame.ts Deprecated/Applications/Samples/Deprecated/Web/single-frame.tsconfig.json Deprecated/Applications/Samples/Deprecated/Web/tsconfig-samples.json Deprecated/Applications/Samples/Deprecated/build-wasm.sh Deprecated/Applications/Samples/Deprecated/build-wasm.sh.old Deprecated/Applications/Samples/Deprecated/build-web-ext.sh Deprecated/Applications/Samples/Deprecated/build-web.sh Deprecated/Applications/Samples/Deprecated/get-requirements-windows.ps1 Deprecated/Applications/Samples/Deprecated/nginx.local.conf Deprecated/Applications/Samples/Deprecated/package-lock.json Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/CMakeLists.txt Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/build-sdl-msvc15.ps1 Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/build-wasm.sh Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/build-web.sh Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/index.html Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/main.cpp Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/nginx.local.conf Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.html Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.ts Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.tsconfig.json Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/samples-styles.css Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/start-serving-files.sh Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/stop-serving-files.sh Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/tsconfig-samples.json Deprecated/Applications/Samples/Deprecated/tsconfig-stone.json Deprecated/Applications/Sdl/SdlCairoSurface.cpp Deprecated/Applications/Sdl/SdlCairoSurface.h Deprecated/Applications/Sdl/SdlEngine.cpp Deprecated/Applications/Sdl/SdlEngine.h Deprecated/Applications/Sdl/SdlOrthancSurface.cpp Deprecated/Applications/Sdl/SdlOrthancSurface.h Deprecated/Applications/Sdl/SdlStoneApplicationRunner.cpp Deprecated/Applications/Sdl/SdlStoneApplicationRunner.h Deprecated/Applications/StoneApplicationContext.cpp Deprecated/Applications/StoneApplicationContext.h Deprecated/Applications/Wasm/StartupParametersBuilder.cpp Deprecated/Applications/Wasm/StartupParametersBuilder.h
diffstat 214 files changed, 12008 insertions(+), 12008 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Commands/BaseCommands.yml	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-SelectTool:
-  target: Application
-  toolName: string
-  comment: Selects the current application tool
-DownloadDicom:
-  target: SliceViewerWidget
-  comment: Downloads the slice currently displayed in the SliceViewerWidget
-Export:
-  target: IWidget
-  comment: Export the content of the widget
\ No newline at end of file
--- a/Applications/Generic/GuiAdapter.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1142 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "GuiAdapter.h"
-
-#if ORTHANC_ENABLE_OPENGL == 1
-#  include "../../Framework/OpenGL/OpenGLIncludes.h"
-#endif
-
-#if ORTHANC_ENABLE_SDL == 1
-#  include <SDL_video.h>
-#  include <SDL_render.h>
-#  include <SDL.h>
-#endif
-
-#if ORTHANC_ENABLE_THREADS == 1
-#  include "../../Framework/Deprecated/Messages/LockingEmitter.h"
-#endif
-
-#include <Core/Compatibility.h>
-
-namespace OrthancStone
-{
-  std::ostream& operator<<(
-    std::ostream& os, const GuiAdapterKeyboardEvent& event)
-  {
-    os << "sym: " << event.sym << " (" << (int)(event.sym[0]) << ") ctrl: " << event.ctrlKey << ", " <<
-      "shift: " << event.shiftKey << ", " <<
-      "alt: " << event.altKey;
-    return os;
-  }
-
-  std::ostream& operator<<(
-    std::ostream& os, const GuiAdapterMouseEvent& event)
-  {
-    os << "targetX: " << event.targetX << " targetY: " << event.targetY << " button: " << event.button
-      << "ctrlKey: " << event.ctrlKey << "shiftKey: " << event.shiftKey << "altKey: " << event.altKey;
-      
-    return os;
-  }
-
-#if ORTHANC_ENABLE_WASM == 1
-  void GuiAdapter::Run(GuiAdapterRunFunc /*func*/, void* /*cookie*/)
-  {
-  }
-
-  void ConvertFromPlatform(
-    GuiAdapterUiEvent& dest,
-    int                      eventType,
-    const EmscriptenUiEvent& src)
-  {
-    // no data for now
-  }
-
-  void ConvertFromPlatform(
-    GuiAdapterMouseEvent& dest,
-    int                         eventType,
-    const EmscriptenMouseEvent& src)
-  {
-    memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
-    switch (eventType)
-    {
-    case EMSCRIPTEN_EVENT_CLICK:
-      LOG(ERROR) << "Emscripten EMSCRIPTEN_EVENT_CLICK is not supported";
-      ORTHANC_ASSERT(false, "Not supported");
-      break;
-    case EMSCRIPTEN_EVENT_MOUSEDOWN:
-      dest.type = GUIADAPTER_EVENT_MOUSEDOWN;
-      break;
-    case EMSCRIPTEN_EVENT_DBLCLICK:
-      dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK;
-      break;
-    case EMSCRIPTEN_EVENT_MOUSEMOVE:
-      dest.type = GUIADAPTER_EVENT_MOUSEMOVE;
-      break;
-    case EMSCRIPTEN_EVENT_MOUSEUP:
-      dest.type = GUIADAPTER_EVENT_MOUSEUP;
-      break;
-    case EMSCRIPTEN_EVENT_WHEEL:
-      dest.type = GUIADAPTER_EVENT_WHEEL;
-      break;
-
-    default:
-      LOG(ERROR) << "Emscripten event: " << eventType << " is not supported";
-      ORTHANC_ASSERT(false, "Not supported");
-    }
-    //dest.timestamp = src.timestamp;
-    //dest.screenX = src.screenX;
-    //dest.screenY = src.screenY;
-    //dest.clientX = src.clientX;
-    //dest.clientY = src.clientY;
-    dest.ctrlKey = src.ctrlKey;
-    dest.shiftKey = src.shiftKey;
-    dest.altKey = src.altKey;
-    //dest.metaKey = src.metaKey;
-    dest.button = src.button;
-    //dest.buttons = src.buttons;
-    //dest.movementX = src.movementX;
-    //dest.movementY = src.movementY;
-    dest.targetX = src.targetX;
-    dest.targetY = src.targetY;
-    //dest.canvasX = src.canvasX;
-    //dest.canvasY = src.canvasY;
-    //dest.padding = src.padding;
-  }
-
-  void ConvertFromPlatform( GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src)
-  {
-    ConvertFromPlatform(dest.mouse, eventType, src.mouse);
-    dest.deltaX = src.deltaX;
-    dest.deltaY = src.deltaY;
-    switch (src.deltaMode)
-    {
-    case DOM_DELTA_PIXEL:
-      dest.deltaMode = GUIADAPTER_DELTA_PIXEL;
-      break;
-    case DOM_DELTA_LINE:
-      dest.deltaMode = GUIADAPTER_DELTA_LINE;
-      break;
-    case DOM_DELTA_PAGE:
-      dest.deltaMode = GUIADAPTER_DELTA_PAGE;
-      break;
-    default:
-      ORTHANC_ASSERT(false, "Unknown deltaMode: " << src.deltaMode <<
-        " in wheel event...");
-    }
-    dest.deltaMode = src.deltaMode;
-  }
-
-  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src)
-  {
-    dest.sym[0] = src.key[0];
-    dest.sym[1] = 0;
-    dest.ctrlKey = src.ctrlKey;
-    dest.shiftKey = src.shiftKey;
-    dest.altKey = src.altKey;
-  }
-
-  template<typename GenericFunc>
-  struct FuncAdapterPayload
-  {
-    std::string canvasCssSelector;
-    void* userData;
-    GenericFunc callback;
-  };
-
-  template<typename GenericFunc,
-    typename GuiAdapterEvent,
-    typename EmscriptenEvent>
-    EM_BOOL OnEventAdapterFunc(
-      int eventType, const EmscriptenEvent* emEvent, void* userData)
-  {
-    // userData is OnMouseWheelFuncAdapterPayload
-    FuncAdapterPayload<GenericFunc>* payload =
-      reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
-    // LOG(INFO) << "OnEventAdapterFunc";
-    // LOG(INFO) << "------------------";
-    // LOG(INFO) << "eventType: " << eventType << " wheelEvent: " << 
-    //   (int)wheelEvent << " userData: " << userData << 
-    //   " payload->userData: " << payload->userData;
-
-    GuiAdapterEvent guiEvent;
-    ConvertFromPlatform(guiEvent, eventType, *emEvent);
-    bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData);
-    return static_cast<EM_BOOL>(ret);
-  }
-
-  template<typename GenericFunc,
-    typename GuiAdapterEvent,
-    typename EmscriptenEvent>
-    EM_BOOL OnEventAdapterFunc2(
-      int /*eventType*/, const EmscriptenEvent* wheelEvent, void* userData)
-  {
-    // userData is OnMouseWheelFuncAdapterPayload
-    FuncAdapterPayload<GenericFunc>* payload =
-      reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
-
-    GuiAdapterEvent guiEvent;
-    ConvertFromPlatform(guiEvent, *wheelEvent);
-    bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData);
-    return static_cast<EM_BOOL>(ret);
-  }
-
-  template<typename GenericFunc>
-  EM_BOOL OnEventAdapterFunc3(
-    double time, void* userData)
-  {
-    // userData is OnMouseWheelFuncAdapterPayload
-    FuncAdapterPayload<GenericFunc>* payload =
-      reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
-    //std::unique_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload);
-    bool ret = (*(payload->callback))(time, payload->userData);
-    return static_cast<EM_BOOL>(ret);
-  }
-
-  /*
-  
-  Explanation
-  ===========
-
-  - in "older" Emscripten, where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR doesn't exist or is set to 0,
-    the following strings need to be used to register events:
-    - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs 
-      to be "mycanvas"
-    - for the window (for key events), the string needs to be "#window"
-  - in newer Emscripten where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR==1 (or maybe is not there anymore, in the
-    future as of 2020-04-20)
-    - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs
-      to be "#mycanvas"  (notice the "number sign", aka "hash", NOT AKA "sharp", as can be read on https://en.wikipedia.org/wiki/Number_sign)
-    - for the window (for key events), the string needs to be EMSCRIPTEN_EVENT_TARGET_WINDOW. I do not mean 
-      "EMSCRIPTEN_EVENT_TARGET_WINDOW", but the #define EMSCRIPTEN_EVENT_TARGET_WINDOW         ((const char*)2) that
-      can be found in emscripten/html5.h
-
-  The code below converts the input canvasId (as in the old emscripten) to the emscripten-compliant one, with the
-  following compile condition : #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1
-
-  If the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR build parameter disappears, you might want to refactor this code
-  or continue to pass the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR compile macro (which is different from the CMake
-  variable)     
-
-  What we are doing below:
-  - in older Emscripten, the registration functions will receive "mycanvas" and "#window" and the callbacks will receive 
-    the same std::string in their payload ("mycanvas" and "#window")
-
-  - in newer Emscripten, the registration functions will receive "#mycanvas" and EMSCRIPTEN_EVENT_TARGET_WINDOW, but 
-    the callbacks will receive "#mycanvas" and "#window" (since it is not possible to store the EMSCRIPTEN_EVENT_TARGET_WINDOW
-    magic value in an std::string, while we still want the callback to be able to change its behavior according to the
-    target element.
-  
-  */
-
-  void convertElementTarget(const char*& outCanvasCssSelectorSz, std::string& outCanvasCssSelector, const std::string& canvasId)
-  {
-    // only "#window" can start with a #
-    if (canvasId[0] == '#')
-    {
-      ORTHANC_ASSERT(canvasId == "#window");
-    }
-#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1
-    if (canvasId == "#window")
-    {
-      // we store this in the payload so that the callback can 
-      outCanvasCssSelector = "#window";
-      outCanvasCssSelectorSz = EMSCRIPTEN_EVENT_TARGET_WINDOW;
-    }
-    else
-    {
-      outCanvasCssSelector = "#" + canvasId;
-      outCanvasCssSelectorSz = outCanvasCssSelector.c_str();
-    }
-#else
-    if (canvasId == "#window")
-    {
-      // we store this in the payload so that the callback can 
-      outCanvasCssSelector = "#window";
-      outCanvasCssSelectorSz = outCanvasCssSelector.c_str();;
-    }
-    else
-    {
-      outCanvasCssSelector = canvasId;
-      outCanvasCssSelectorSz = outCanvasCssSelector.c_str();;
-    }
-#endif
-  }
-
-  // resize: (const char* target, void* userData, EM_BOOL useCapture, em_ui_callback_func callback)
-  template<
-    typename GenericFunc,
-    typename GuiAdapterEvent,
-    typename EmscriptenEvent,
-    typename EmscriptenSetCallbackFunc>
-    static void SetCallback(
-      EmscriptenSetCallbackFunc emFunc,
-      std::string canvasId, void* userData, bool capture, GenericFunc func)
-  {
-    std::string canvasCssSelector;
-    const char* canvasCssSelectorSz = NULL;
-    convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId);
-
-    // TODO: write RemoveCallback with an int id that gets returned from here
-
-    // create userdata payload
-    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>());
-    payload->canvasCssSelector = canvasCssSelector;
-    payload->callback = func;
-    payload->userData = userData;
-    void* userDataRaw = reinterpret_cast<void*>(payload.release());
-
-    // call the registration function
-    (*emFunc)(
-      canvasCssSelectorSz,
-      userDataRaw,
-      static_cast<EM_BOOL>(capture),
-      &OnEventAdapterFunc<GenericFunc, GuiAdapterEvent, EmscriptenEvent>,
-      EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD);
-  }
-
-  template<
-    typename GenericFunc,
-    typename GuiAdapterEvent,
-    typename EmscriptenEvent,
-    typename EmscriptenSetCallbackFunc>
-    static void SetCallback2(
-      EmscriptenSetCallbackFunc emFunc,
-      std::string canvasId, void* userData, bool capture, GenericFunc func)
-  {
-    std::string canvasCssSelector;
-    const char* canvasCssSelectorSz = NULL;
-    convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId);
-
-    // TODO: write RemoveCallback with an int id that gets returned from here
-
-    // create userdata payload
-    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>());
-    payload->canvasCssSelector = canvasCssSelector;
-    payload->callback = func;
-    payload->userData = userData;
-    void* userDataRaw = reinterpret_cast<void*>(payload.release());
-
-    // call the registration function
-    (*emFunc)(
-      canvasCssSelectorSz,
-      userDataRaw,
-      static_cast<EM_BOOL>(capture),
-      &OnEventAdapterFunc2<GenericFunc, GuiAdapterEvent, EmscriptenEvent>,
-      EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD);
-  }
-
-  template<
-    typename GenericFunc,
-    typename EmscriptenSetCallbackFunc>
-    static void SetAnimationFrameCallback(
-      EmscriptenSetCallbackFunc emFunc,
-      void* userData, GenericFunc func)
-  {
-    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(
-      new FuncAdapterPayload<GenericFunc>()
-    );
-    payload->canvasCssSelector = "UNDEFINED";
-    payload->callback = func;
-    payload->userData = userData;
-    void* userDataRaw = reinterpret_cast<void*>(payload.release());
-    (*emFunc)(
-      &OnEventAdapterFunc3<GenericFunc>,
-      userDataRaw);
-  }
-
-  void GuiAdapter::SetWheelCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func)
-  {
-    SetCallback<OnMouseWheelFunc, GuiAdapterWheelEvent, EmscriptenWheelEvent>(
-      &emscripten_set_wheel_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-  
-  void GuiAdapter::SetMouseDblClickCallback(
-      std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
-  {
-    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
-      &emscripten_set_dblclick_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-
-  void GuiAdapter::SetMouseDownCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
-  {
-    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
-      &emscripten_set_mousedown_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-  void GuiAdapter::SetMouseMoveCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
-  {
-    // LOG(INFO) << "SetMouseMoveCallback -- " << "supplied userData: " << 
-    //   userData;
-
-    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
-      &emscripten_set_mousemove_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-  void GuiAdapter::SetMouseUpCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
-  {
-    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
-      &emscripten_set_mouseup_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-  void GuiAdapter::SetKeyDownCallback(
-    std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
-  {
-    SetCallback2<OnKeyDownFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>(
-      &emscripten_set_keydown_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-  void GuiAdapter::SetKeyUpCallback(
-    std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
-  {
-    SetCallback2<OnKeyUpFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>(
-      &emscripten_set_keyup_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-
-#if 0
-  // useless under Wasm where canvas resize is handled automatically
-  void GuiAdapter::SetResizeCallback(
-    std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
-  {
-    SetCallback<OnWindowResizeFunc, GuiAdapterUiEvent, EmscriptenUiEvent>(
-      &emscripten_set_resize_callback_on_thread,
-      canvasId,
-      userData,
-      capture,
-      func);
-  }
-#endif
-
-  void GuiAdapter::RequestAnimationFrame(
-    OnAnimationFrameFunc func, void* userData)
-  {
-    SetAnimationFrameCallback<OnAnimationFrameFunc>(
-      &emscripten_request_animation_frame_loop,
-      userData,
-      func);
-  }
-
-#if 0
-  void GuiAdapter::SetKeyDownCallback(
-    std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
-  {
-    emscripten_set_keydown_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
-  }
-  void GuiAdapter::SetKeyUpCallback(
-    std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
-  {
-    emscripten_set_keyup_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
-  }
-
-  // handled from within WebAssemblyViewport
-  //void GuiAdapter::SetResizeCallback(std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
-  //{
-  //  emscripten_set_resize_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
-  //}
-
-  void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
-  {
-    emscripten_request_animation_frame_loop(func, userData);
-  }
-#endif
-
-
-#else
-
-  // SDL ONLY
-  void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source)
-  {
-    memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
-    switch (source.type)
-    {
-    case SDL_MOUSEBUTTONDOWN:
-      if (source.button.clicks == 1) {
-        dest.type = GUIADAPTER_EVENT_MOUSEDOWN;
-      } else if (source.button.clicks == 2) {
-        dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK;
-      } else {
-        dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK;
-        LOG(WARNING) << "Multiple-click ignored.";
-      }
-      break;
-    case SDL_MOUSEMOTION:
-      dest.type = GUIADAPTER_EVENT_MOUSEMOVE;
-      break;
-    case SDL_MOUSEBUTTONUP:
-      dest.type = GUIADAPTER_EVENT_MOUSEUP;
-      break;
-    case SDL_MOUSEWHEEL:
-      dest.type = GUIADAPTER_EVENT_WHEEL;
-      break;
-    default:
-      LOG(ERROR) << "SDL event: " << source.type << " is not supported";
-      ORTHANC_ASSERT(false, "Not supported");
-    }
-    //dest.timestamp = src.timestamp;
-    //dest.screenX = src.screenX;
-    //dest.screenY = src.screenY;
-    //dest.clientX = src.clientX;
-    //dest.clientY = src.clientY;
-    dest.ctrlKey = ctrlPressed;
-    dest.shiftKey = shiftPressed;
-    dest.altKey = altPressed;
-    //dest.metaKey = src.metaKey;
-    switch (source.button.button)
-    {
-    case SDL_BUTTON_MIDDLE:
-      dest.button =GUIADAPTER_MOUSEBUTTON_MIDDLE;
-      break;
-
-    case SDL_BUTTON_RIGHT:
-      dest.button = GUIADAPTER_MOUSEBUTTON_RIGHT;
-      break;
-
-    case SDL_BUTTON_LEFT:
-      dest.button = GUIADAPTER_MOUSEBUTTON_LEFT;
-      break;
-
-    default:
-      break;
-    }
-    //dest.buttons = src.buttons;
-    //dest.movementX = src.movementX;
-    //dest.movementY = src.movementY;
-    dest.targetX = source.button.x;
-    dest.targetY = source.button.y;
-    //dest.canvasX = src.canvasX;
-    //dest.canvasY = src.canvasY;
-    //dest.padding = src.padding;
-  }
-
-  void ConvertFromPlatform(
-    GuiAdapterWheelEvent& dest,
-    bool ctrlPressed, bool shiftPressed, bool altPressed,
-    const SDL_Event& source)
-  {
-    ConvertFromPlatform(dest.mouse, ctrlPressed, shiftPressed, altPressed, source);
-    dest.deltaX = source.wheel.x;
-    dest.deltaY = source.wheel.y;
-  }
-
-  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& src)
-  {
-    memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
-    switch (src.type)
-    {
-    case SDL_KEYDOWN:
-      dest.type = GUIADAPTER_EVENT_KEYDOWN;
-      break;
-    case SDL_KEYUP:
-      dest.type = GUIADAPTER_EVENT_KEYUP;
-      break;
-    default:
-      LOG(ERROR) << "SDL event: " << src.type << " is not supported";
-      ORTHANC_ASSERT(false, "Not supported");
-    }
-    dest.sym[0] = src.key.keysym.sym;
-    dest.sym[1] = 0;
-
-    if (src.key.keysym.mod & KMOD_CTRL)
-      dest.ctrlKey = true;
-    else
-      dest.ctrlKey = false;
-
-    if (src.key.keysym.mod & KMOD_SHIFT)
-      dest.shiftKey = true;
-    else
-      dest.shiftKey = false;
-
-    if (src.key.keysym.mod & KMOD_ALT)
-      dest.altKey = true;
-    else
-      dest.altKey = false;
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetSdlResizeCallback(
-    std::string canvasId, void* userData, bool capture, OnSdlWindowResizeFunc func)
-  {
-    resizeHandlers_.push_back(EventHandlerData<OnSdlWindowResizeFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetMouseDownCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
-  {
-    mouseDownHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetMouseDblClickCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
-  {
-    mouseDblCickHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetMouseMoveCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc  func)
-  {
-    mouseMoveHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetMouseUpCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseEventFunc  func)
-  {
-    mouseUpHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetWheelCallback(
-    std::string canvasId, void* userData, bool capture, OnMouseWheelFunc  func)
-  {
-    mouseWheelHandlers_.push_back(EventHandlerData<OnMouseWheelFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetKeyDownCallback(
-    std::string canvasId, void* userData, bool capture, OnKeyDownFunc   func)
-  {
-    keyDownHandlers_.push_back(EventHandlerData<OnKeyDownFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetKeyUpCallback(
-    std::string canvasId, void* userData, bool capture, OnKeyUpFunc    func)
-  {
-    keyUpHandlers_.push_back(EventHandlerData<OnKeyUpFunc>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::SetGenericSdlEventCallback(
-    std::string canvasId, void* userData, bool capture, OnSdlEventCallback func)
-  {
-    sdlEventHandlers_.push_back(EventHandlerData<OnSdlEventCallback>(canvasId, func, userData));
-  }
-
-  // SDL ONLY
-  void GuiAdapter::OnAnimationFrame()
-  {
-    std::vector<size_t> disabledAnimationHandlers;
-    for (size_t i = 0; i < animationFrameHandlers_.size(); i++)
-    {
-      // TODO: fix time 
-      bool goOn = (*(animationFrameHandlers_[i].first))(0, animationFrameHandlers_[i].second);
-
-      // If the function returns false, we need to emulate what happens in Web 
-      // and remove the function from the handlers...
-      if (!goOn)
-        disabledAnimationHandlers.push_back(i);
-    }
-    for (size_t i = 0; i < disabledAnimationHandlers.size(); i++)
-    {
-      ORTHANC_ASSERT(animationFrameHandlers_.begin() + disabledAnimationHandlers[i] < animationFrameHandlers_.end());
-      animationFrameHandlers_.erase(animationFrameHandlers_.begin() + disabledAnimationHandlers[i]);
-    }
-  }
-
-  // SDL ONLY
-  void GuiAdapter::OnResize(unsigned int width, unsigned int height)
-  {
-    for (size_t i = 0; i < resizeHandlers_.size(); i++)
-    {
-      (*(resizeHandlers_[i].func))(
-        resizeHandlers_[i].canvasName, NULL, width, height, resizeHandlers_[i].userData);
-    }
-  }
-
-
-
-  void GuiAdapter::OnSdlGenericEvent(const SDL_Event& sdlEvent)
-  {
-    // Events related to a window are only sent to the related canvas
-    // User events are sent to everyone (we can't filter them here)
-    
-    /*
-    SDL_WindowEvent    SDL_WINDOWEVENT
-    SDL_KeyboardEvent     SDL_KEYDOWN
-                          SDL_KEYUP
-    SDL_TextEditingEvent  SDL_TEXTEDITING
-    SDL_TextInputEvent    SDL_TEXTINPUT
-    SDL_MouseMotionEvent  SDL_MOUSEMOTION
-    SDL_MouseButtonEvent  SDL_MOUSEBUTTONDOWN 
-                          SDL_MOUSEBUTTONUP
-    SDL_MouseWheelEvent   SDL_MOUSEWHEEL
-    SDL_UserEvent         SDL_USEREVENT through ::SDL_LASTEVENT-1
-    */
-
-    // if this string is left empty, it means the message will be sent to
-    // all widgets.
-    // otherwise, it contains the originating message window title
-
-    std::string windowTitle;
-    uint32_t windowId = 0;
-
-    if (sdlEvent.type == SDL_WINDOWEVENT)
-      windowId = sdlEvent.window.windowID;
-    else if (sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP)
-      windowId = sdlEvent.key.windowID;
-    else if (sdlEvent.type == SDL_TEXTEDITING)
-      windowId = sdlEvent.edit.windowID;
-    else if (sdlEvent.type == SDL_TEXTINPUT)
-      windowId = sdlEvent.text.windowID;
-    else if (sdlEvent.type == SDL_MOUSEMOTION)
-      windowId = sdlEvent.motion.windowID;
-    else if (sdlEvent.type == SDL_MOUSEBUTTONDOWN || sdlEvent.type == SDL_MOUSEBUTTONUP)
-      windowId = sdlEvent.button.windowID;
-    else if (sdlEvent.type == SDL_MOUSEWHEEL)
-      windowId = sdlEvent.wheel.windowID;
-    else if (sdlEvent.type >= SDL_USEREVENT && sdlEvent.type <= (SDL_LASTEVENT-1))
-      windowId = sdlEvent.user.windowID;
-
-    if (windowId != 0)
-    {
-      SDL_Window* sdlWindow = SDL_GetWindowFromID(windowId);
-      ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowId << "\" is not a valid SDL window ID!");
-      const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
-      ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowId << "\" has a NULL window title!");
-      windowTitle = windowTitleSz;
-      ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowId << "\" has an empty window title!");
-    }
-
-    for (size_t i = 0; i < sdlEventHandlers_.size(); i++)
-    {
-      // normally, the handlers return a bool indicating whether they
-      // have handled the event or not, but we don't really care about this
-      std::string& canvasName = sdlEventHandlers_[i].canvasName;
-      
-      bool sendEvent = true;
-
-      if (windowTitle != "" && (canvasName != windowTitle))
-        sendEvent = false;
-
-      if (sendEvent)
-      {
-        OnSdlEventCallback func = sdlEventHandlers_[i].func;
-        (*func)(canvasName, sdlEvent, sdlEventHandlers_[i].userData);
-      }
-    }
-  }
-
-  // SDL ONLY
-  void GuiAdapter::OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event)
-  {
-    // the SDL window name IS the canvas name ("canvas" is used because this lib
-    // is designed for Wasm
-    SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID);
-    ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!");
-
-    const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
-    ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!");
-
-    std::string windowTitle(windowTitleSz);
-    ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!");
-
-    switch (event.mouse.type)
-    {
-    case GUIADAPTER_EVENT_WHEEL:
-      for (size_t i = 0; i < mouseWheelHandlers_.size(); i++)
-      {
-        if (mouseWheelHandlers_[i].canvasName == windowTitle)
-          (*(mouseWheelHandlers_[i].func))(windowTitle, &event, mouseWheelHandlers_[i].userData);
-      }
-      break;
-    default:
-      ORTHANC_ASSERT(false, "Wrong event.type: " << event.mouse.type << " in GuiAdapter::OnMouseWheelEvent(...)");
-      break;
-    }
-  }
-
-
-  void GuiAdapter::OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event)
-  {
-    // only one-letter (ascii) keyboard events supported for now
-    ORTHANC_ASSERT(event.sym[0] != 0);
-    ORTHANC_ASSERT(event.sym[1] == 0);
-
-    SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID);
-    ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!");
-
-    const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
-    ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!");
-
-    std::string windowTitle(windowTitleSz);
-    ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!");
-
-    switch (event.type)
-    {
-    case GUIADAPTER_EVENT_KEYDOWN:
-      for (size_t i = 0; i < keyDownHandlers_.size(); i++)
-      {
-        (*(keyDownHandlers_[i].func))(windowTitle, &event, keyDownHandlers_[i].userData);
-      }
-      break;
-    case GUIADAPTER_EVENT_KEYUP:
-      for (size_t i = 0; i < keyUpHandlers_.size(); i++)
-      {
-        (*(keyUpHandlers_[i].func))(windowTitle, &event, keyUpHandlers_[i].userData);
-      }
-      break;
-    default:
-      ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnKeyboardEvent(...)");
-      break;
-    }
-  }
-
-  // SDL ONLY
-  void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event)
-  {
-    if (windowID == 0)
-    {
-      LOG(WARNING) << "GuiAdapter::OnMouseEvent -- windowID == 0 and event won't be routed!";
-    }
-    else
-    {
-      // the SDL window name IS the canvas name ("canvas" is used because this lib
-      // is designed for Wasm
-      SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID);
-
-      ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!");
-
-      const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
-      ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!");
-
-      std::string windowTitle(windowTitleSz);
-      ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!");
-
-      switch (event.type)
-      {
-      case GUIADAPTER_EVENT_MOUSEDOWN:
-        for (size_t i = 0; i < mouseDownHandlers_.size(); i++)
-        {
-          if (mouseDownHandlers_[i].canvasName == windowTitle)
-            (*(mouseDownHandlers_[i].func))(windowTitle, &event, mouseDownHandlers_[i].userData);
-        }
-        break;
-      case GUIADAPTER_EVENT_MOUSEDBLCLICK:
-        for (size_t i = 0; i < mouseDblCickHandlers_.size(); i++)
-        {
-          if (mouseDblCickHandlers_[i].canvasName == windowTitle)
-            (*(mouseDblCickHandlers_[i].func))(windowTitle, &event, mouseDblCickHandlers_[i].userData);
-        }
-        break;
-      case GUIADAPTER_EVENT_MOUSEMOVE:
-        for (size_t i = 0; i < mouseMoveHandlers_.size(); i++)
-        {
-          if (mouseMoveHandlers_[i].canvasName == windowTitle)
-            (*(mouseMoveHandlers_[i].func))(windowTitle, &event, mouseMoveHandlers_[i].userData);
-        }
-        break;
-      case GUIADAPTER_EVENT_MOUSEUP:
-        for (size_t i = 0; i < mouseUpHandlers_.size(); i++)
-        {
-          if (mouseUpHandlers_[i].canvasName == windowTitle)
-            (*(mouseUpHandlers_[i].func))(windowTitle, &event, mouseUpHandlers_[i].userData);
-        }
-        break;
-      default:
-        ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)");
-        break;
-      }
-    }
-  }
-
-
-  // extern void Debug_SetContextToBeKilled(std::string title);
-  // extern void Debug_SetContextToBeRestored(std::string title);
-
-  // SDL ONLY
-  void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
-  {
-    animationFrameHandlers_.push_back(std::make_pair(func, userData));
-  }
-
-# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__)   /* OpenGL debug is not available on OS X */
-
-  // SDL ONLY
-  static void GLAPIENTRY
-    OpenGLMessageCallback(GLenum source,
-      GLenum type,
-      GLuint id,
-      GLenum severity,
-      GLsizei length,
-      const GLchar * message,
-      const void* userParam)
-  {
-    if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
-    {
-      fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
-        (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
-        type, severity, message);
-    }
-  }
-# endif
-
-#if 0
-  // TODO: remove this when generic sdl event handlers are implemented in 
-  // the DoseView
-  // SDL ONLY
-  bool GuiAdapter::IsSdlViewPortRefreshEvent(const SDL_Event& event) const
-  {
-    SDL_Window* sdlWindow = SDL_GetWindowFromID(event.window.windowID);
-
-    ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << event.window.windowID << "\" is not a valid SDL window ID!");
-
-    const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
-
-    // now we need to find the DoseView from from the canvas name!
-    // (and retrieve the SdlViewport)
-    boost::shared_ptr<IGuiAdapterWidget> foundWidget;
-    VisitWidgets([&foundWidget, windowTitleSz](auto widget)
-    {
-      if (widget->GetCanvasIdentifier() == std::string(windowTitleSz))
-        foundWidget = widget;
-    });
-    ORTHANC_ASSERT(foundWidget, "The window named: \"" << windowTitleSz << "\" was not found in the registered widgets!");
-    return foundWidget->GetSdlViewport().IsRefreshEvent(event);
-  }
-#endif
-
-  // SDL ONLY
-  void GuiAdapter::Run(GuiAdapterRunFunc func, void* cookie)
-  {
-#if 1
-    // TODO: MAKE THIS DYNAMIC !!! See SdlOpenGLViewport vs Cairo in ViewportWrapper
-# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__)
-    glEnable(GL_DEBUG_OUTPUT);
-    glDebugMessageCallback(OpenGLMessageCallback, 0);
-# endif
-#endif
-
-    // Uint32 SDL_GetWindowID(SDL_Window* window)
-    // SDL_Window* SDL_GetWindowFromID(Uint32 id)   // may return NULL
-
-    bool stop = false;
-    while (!stop)
-    {
-      {
-        // TODO: lock all viewports here! (use a scoped object)
-        if(func != NULL)
-          (*func)(cookie);
-        OnAnimationFrame(); // in SDL we must call it
-      }
-
-      while (!stop)
-      {
-        std::vector<SDL_Event> sdlEvents;
-        std::map<Uint32,SDL_Event> userEventsMap;
-        
-        SDL_Event sdlEvent;
-
-        // FIRST: collect all pending events
-        while (SDL_PollEvent(&sdlEvent) != 0)
-        {
-          if ( (sdlEvent.type >= SDL_USEREVENT) && 
-               (sdlEvent.type <= SDL_USEREVENT) )
-          {
-            // we don't want to have multiple events with the same event.type
-            userEventsMap[sdlEvent.type] = sdlEvent;
-          }
-          else
-          {
-            sdlEvents.push_back(sdlEvent);
-          }
-        }
-
-        // SECOND: collect all user events
-        for (std::map<Uint32,SDL_Event>::const_iterator it = userEventsMap.begin(); it != userEventsMap.end(); ++it)
-          sdlEvents.push_back(it->second);
-                
-        // now process the events
-        for (std::vector<SDL_Event>::const_iterator it = sdlEvents.begin(); it != sdlEvents.end(); ++it)
-        {
-          const SDL_Event& sdlEvent = *it;
-          // TODO: lock all viewports here! (use a scoped object)
-
-          if (sdlEvent.type == SDL_QUIT)
-          {
-            // TODO: call exit callbacks here
-            stop = true;
-            break;
-          }
-          else if ((sdlEvent.type == SDL_MOUSEMOTION) ||
-            (sdlEvent.type == SDL_MOUSEBUTTONDOWN) ||
-                   (sdlEvent.type == SDL_MOUSEBUTTONUP))
-          {
-            int scancodeCount = 0;
-            const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
-            bool ctrlPressed(false);
-            bool shiftPressed(false);
-            bool altPressed(false);
-
-            if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL])
-              ctrlPressed = true;
-            if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL])
-              ctrlPressed = true;
-            if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT])
-              shiftPressed = true;
-            if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT])
-              shiftPressed = true;
-            if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT])
-              altPressed = true;
-
-            GuiAdapterMouseEvent dest;
-            ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent);
-            OnMouseEvent(sdlEvent.window.windowID, dest);
-  #if 0
-            // for reference, how to create trackers
-            if (tracker)
-            {
-              PointerEvent e;
-              e.AddPosition(compositor.GetPixelCenterCoordinates(
-                sdlEvent.button.x, sdlEvent.button.y));
-              tracker->PointerMove(e);
-            }
-  #endif
-          }
-          else if (sdlEvent.type == SDL_MOUSEWHEEL)
-          {
-
-            int scancodeCount = 0;
-            const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
-            bool ctrlPressed(false);
-            bool shiftPressed(false);
-            bool altPressed(false);
-
-            if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL])
-              ctrlPressed = true;
-            if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL])
-              ctrlPressed = true;
-            if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT])
-              shiftPressed = true;
-            if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT])
-              shiftPressed = true;
-            if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT])
-              altPressed = true;
-
-            GuiAdapterWheelEvent dest;
-            ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent);
-            OnMouseWheelEvent(sdlEvent.window.windowID, dest);
-
-            //KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
-
-            //int x, y;
-            //SDL_GetMouseState(&x, &y);
-
-            //if (sdlEvent.wheel.y > 0)
-            //{
-            //  locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers);
-            //}
-            //else if (sdlEvent.wheel.y < 0)
-            //{
-            //  locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
-            //}
-          }
-          else if (sdlEvent.type == SDL_WINDOWEVENT &&
-            (sdlEvent.window.event == SDL_WINDOWEVENT_RESIZED ||
-             sdlEvent.window.event == SDL_WINDOWEVENT_SIZE_CHANGED))
-          {
-  #if 0
-            tracker.reset();
-  #endif
-            OnResize(sdlEvent.window.data1, sdlEvent.window.data2);
-          }
-          else if (sdlEvent.type == SDL_KEYDOWN && sdlEvent.key.repeat == 0 /* Ignore key bounce */)
-          {
-            switch (sdlEvent.key.keysym.sym)
-            {
-            case SDLK_f:
-              // window.GetWindow().ToggleMaximize(); //TODO: move to particular handler
-              break;
-
-            // This commented out code was used to debug the context
-            // loss/restoring code (2019-08-10)
-            // case SDLK_k:
-            //   {
-            //     SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID);
-            //     std::string windowTitle(SDL_GetWindowTitle(window));
-            //     Debug_SetContextToBeKilled(windowTitle);
-            //   }
-            //   break;
-            // case SDLK_l:
-            //   {
-            //     SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID);
-            //     std::string windowTitle(SDL_GetWindowTitle(window));
-            //     Debug_SetContextToBeRestored(windowTitle);
-            //   }
-            //   break;
-
-            case SDLK_q:
-              stop = true;
-              break;
-
-            default:
-              GuiAdapterKeyboardEvent dest;
-              ConvertFromPlatform(dest, sdlEvent);
-              OnKeyboardEvent(sdlEvent.window.windowID, dest);
-              break;
-            }
-          }
-        
-          OnSdlGenericEvent(sdlEvent);
-        }
-      }
-
-      SDL_Delay(1);
-    }
-  }
-#endif
-}
-
--- a/Applications/Generic/GuiAdapter.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,375 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-#pragma once
-
-#include <string>
-
-#if ORTHANC_ENABLE_WASM != 1
-# ifdef __EMSCRIPTEN__
-#   error __EMSCRIPTEN__ is defined and ORTHANC_ENABLE_WASM != 1
-# endif
-#endif
-
-#if ORTHANC_ENABLE_WASM == 1
-# ifndef __EMSCRIPTEN__
-#   error __EMSCRIPTEN__ is not defined and ORTHANC_ENABLE_WASM == 1
-# endif
-#endif
-
-#if ORTHANC_ENABLE_WASM == 1
-# include <emscripten/html5.h>
-#else
-# if ORTHANC_ENABLE_SDL == 1
-#   include <SDL.h>
-# endif
-#endif
-
-#include "../../Framework/StoneException.h"
-
-#if ORTHANC_ENABLE_THREADS == 1
-# include "../../Framework/Deprecated/Messages/LockingEmitter.h"
-#endif
-
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
-
-namespace OrthancStone
-{
-#if ORTHANC_ENABLE_SDL == 1
-  class SdlViewport;
-#endif
-
-#if 0
-
-  /**
-  This interface is used to store the widgets that are controlled by the 
-  GuiAdapter and receive event callbacks.
-  The callbacks may possibly be downcast (using dynamic_cast, for safety) \
-  to the actual widget type
-  */
-  class IGuiAdapterWidget
-  {
-  public:
-    virtual ~IGuiAdapterWidget() {}
-    
-#if #if ORTHANC_ENABLE_SDL == 1
-    /**
-    Returns the SdlViewport that this widget contains. If the underlying 
-    viewport type is *not* SDL, then an error is returned.
-    */
-    virtual SdlViewport& GetSdlViewport() = 0;
-#endif
-  };
-
-#endif
-
-  enum GuiAdapterMouseButtonType
-  {
-    GUIADAPTER_MOUSEBUTTON_LEFT = 0,
-    GUIADAPTER_MOUSEBUTTON_MIDDLE = 1,
-    GUIADAPTER_MOUSEBUTTON_RIGHT = 2
-  };
-
-
-  enum GuiAdapterHidEventType
-  {
-    GUIADAPTER_EVENT_MOUSEDOWN      = 1973,
-    GUIADAPTER_EVENT_MOUSEMOVE      = 1974,
-    GUIADAPTER_EVENT_MOUSEDBLCLICK  = 1975,
-    GUIADAPTER_EVENT_MOUSEUP        = 1976,
-    GUIADAPTER_EVENT_WHEEL          = 1977,
-    GUIADAPTER_EVENT_KEYDOWN        = 1978,
-    GUIADAPTER_EVENT_KEYUP          = 1979,
-  };
-
-  const unsigned int GUIADAPTER_DELTA_PIXEL = 2973;
-  const unsigned int GUIADAPTER_DELTA_LINE  = 2974;
-  const unsigned int GUIADAPTER_DELTA_PAGE  = 2975;
-
-  struct GuiAdapterUiEvent;
-  struct GuiAdapterMouseEvent;
-  struct GuiAdapterWheelEvent;
-  struct GuiAdapterKeyboardEvent;
-
-#if 1
-  typedef bool (*OnMouseEventFunc)    (std::string canvasId, const GuiAdapterMouseEvent* mouseEvent, void* userData);
-  typedef bool (*OnMouseWheelFunc)    (std::string canvasId, const GuiAdapterWheelEvent* wheelEvent, void* userData);
-  typedef bool (*OnKeyDownFunc)       (std::string canvasId, const GuiAdapterKeyboardEvent*   keyEvent,   void* userData);
-  typedef bool (*OnKeyUpFunc)         (std::string canvasId, const GuiAdapterKeyboardEvent*   keyEvent,   void* userData);
-  typedef bool (*OnAnimationFrameFunc)(double time, void* userData);
-  
-#if ORTHANC_ENABLE_SDL == 1
-  typedef bool (*OnSdlEventCallback)  (std::string canvasId, const SDL_Event& sdlEvent, void* userData);
-
-  typedef bool (*OnSdlWindowResizeFunc)(std::string canvasId, 
-                                        const GuiAdapterUiEvent* uiEvent, 
-                                        unsigned int width, 
-                                        unsigned int height, 
-                                        void* userData);
-
-
-#endif
-
-#else
-
-#if ORTHANC_ENABLE_WASM == 1
-  typedef EM_BOOL (*OnMouseEventFunc)(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
-  typedef EM_BOOL (*OnMouseWheelFunc)(int eventType, const EmscriptenWheelEvent* wheelEvent, void* userData);
-  typedef EM_BOOL (*OnKeyDownFunc)   (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
-  typedef EM_BOOL (*OnKeyUpFunc)     (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
-
-  typedef EM_BOOL (*OnAnimationFrameFunc)(double time, void* userData);
-  typedef EM_BOOL (*OnWindowResizeFunc)(int eventType, const EmscriptenUiEvent* uiEvent, void* userData);
-#else
-  typedef bool    (*OnMouseEventFunc)(int eventType, const SDL_Event* mouseEvent, void* userData);
-  typedef bool    (*OnMouseWheelFunc)(int eventType, const SDL_Event* wheelEvent, void* userData);
-  typedef bool    (*OnKeyDownFunc)   (int eventType, const SDL_Event* keyEvent,   void* userData);
-  typedef bool    (*OnKeyUpFunc)     (int eventType, const SDL_Event* keyEvent,   void* userData);
-
-  typedef bool    (*OnAnimationFrameFunc)(double time, void* userData);
-  typedef bool    (*OnWindowResizeFunc)(int eventType, const GuiAdapterUiEvent* uiEvent, void* userData);
-#endif
-
-#endif
-  struct GuiAdapterMouseEvent
-  {
-    GuiAdapterHidEventType type;
-    //double                   timestamp;
-    //long                     screenX;
-    //long                     screenY;
-    //long                     clientX;
-    //long                     clientY;
-    bool                     ctrlKey;
-    bool                     shiftKey;
-    bool                     altKey;
-    //bool                     metaKey;
-    unsigned short           button;
-    //unsigned short           buttons;
-    //long                     movementX;
-    //long                     movementY;
-    long                     targetX;
-    long                     targetY;
-    // canvasX and canvasY are deprecated - there no longer exists a Module['canvas'] object, so canvasX/Y are no longer reported (register a listener on canvas directly to get canvas coordinates, or translate manually)
-    //long                     canvasX;
-    //long                     canvasY;
-    //long                     padding;
-
-  public:
-    GuiAdapterMouseEvent()
-      : ctrlKey(false),
-        shiftKey(false),
-        altKey(false)
-    {
-    }
-  };
-
-  struct GuiAdapterWheelEvent {
-    GuiAdapterMouseEvent mouse;
-    double deltaX;
-    double deltaY;
-    unsigned long deltaMode;
-  };
-
-  // we don't use any data now
-  struct GuiAdapterUiEvent {};
-
-  // EmscriptenKeyboardEvent
-  struct GuiAdapterKeyboardEvent
-  {
-    GuiAdapterHidEventType type;
-    char sym[32];
-    bool ctrlKey;
-    bool shiftKey;
-    bool altKey;
-  };
-
-  std::ostream& operator<<(std::ostream& os, const GuiAdapterKeyboardEvent& event);
-  std::ostream& operator<<(std::ostream& os, const GuiAdapterMouseEvent& event);
-
-  /*
-    Mousedown event trigger when either the left or right (or middle) mouse is pressed 
-    on the object;
-
-    Mouseup event trigger when either the left or right (or middle) mouse is released
-    above the object after triggered mousedown event and held.
-
-    Click event trigger when the only left mouse button is pressed and released on the
-    same object, requires the Mousedown and Mouseup event happened before Click event.
-
-    The normal expect trigger order: onMousedown >> onMouseup >> onClick
-
-    Testing in Chrome v58, the time between onMouseup and onClick events are around 
-    7ms to 15ms
-
-    FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/
-  */
-#if ORTHANC_ENABLE_WASM == 1
-  void ConvertFromPlatform(GuiAdapterUiEvent& dest, int eventType, const EmscriptenUiEvent& src);
-
-  void ConvertFromPlatform(GuiAdapterMouseEvent& dest, int eventType, const EmscriptenMouseEvent& src);
-  
-  void ConvertFromPlatform(GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src);
-
-  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src);
-#else
-
-# if ORTHANC_ENABLE_SDL == 1
-  void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source);
-
-  void ConvertFromPlatform(GuiAdapterWheelEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source);
-
-  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& source);
-
-# endif
-
-#endif
-
-  typedef void (*GuiAdapterRunFunc)(void*);
-
-  class GuiAdapter
-  {
-  public:
-    GuiAdapter()
-    {
-      static int instanceCount = 0;
-      ORTHANC_ASSERT(instanceCount == 0);
-      instanceCount = 1;
-    }
-
-    /**
-      emscripten_set_resize_callback("EMSCRIPTEN_EVENT_TARGET_WINDOW", NULL, false, OnWindowResize);
-
-      emscripten_set_wheel_callback("#mycanvas1", widget1_.get(), false, OnXXXMouseWheel);
-      emscripten_set_wheel_callback("#mycanvas2", widget2_.get(), false, OnXXXMouseWheel);
-      emscripten_set_wheel_callback("#mycanvas3", widget3_.get(), false, OnXXXMouseWheel);
-
-      emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyDown); ---> NO!
-      emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyUp);
-
-      emscripten_request_animation_frame_loop(OnAnimationFrame, NULL);
-    
-      SDL:
-      see https://wiki.libsdl.org/SDL_CaptureMouse
-
-    */
-
-    void SetMouseDownCallback       (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
-    void SetMouseDblClickCallback   (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
-    void SetMouseMoveCallback       (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
-    void SetMouseUpCallback         (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
-    void SetWheelCallback           (std::string canvasId, void* userData, bool capture, OnMouseWheelFunc   func);
-    void SetKeyDownCallback         (std::string canvasId, void* userData, bool capture, OnKeyDownFunc      func);
-    void SetKeyUpCallback           (std::string canvasId, void* userData, bool capture, OnKeyUpFunc        func);
-
-#if ORTHANC_ENABLE_SDL == 1
-
-    void SetGenericSdlEventCallback (std::string canvasId, void* userData, bool capture, OnSdlEventCallback func);
-
-    typedef bool (*OnSdlEventCallback)  (std::string canvasId, const SDL_Event& sdlEvent, void* userData);
-
-    // if you pass "#window", then any Window resize will trigger the callback
-    // (this special string is converted to EMSCRIPTEN_EVENT_TARGET_WINDOW in DOM, when DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1)
-    void SetSdlResizeCallback(std::string canvasId, 
-                              void* userData, 
-                              bool capture, 
-                              OnSdlWindowResizeFunc func);
-#endif
-
-    void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
-
-    // TODO: implement and call to remove canvases [in SDL, although code should be generic]
-    void SetOnExitCallback();
-
-    /**
-    Under SDL, this function does NOT return until all windows have been closed.
-    Under wasm, it returns without doing anything, since the event loop is managed
-    by the browser.
-    */
-    void Run(GuiAdapterRunFunc func = NULL, void* cookie = NULL);
-
-  private:
-
-#if ORTHANC_ENABLE_SDL == 1
-    /**
-    Gives observers a chance to react based on generic event handlers. This 
-    is used, for instance, when the viewport lock interface is invalidated.
-    */
-    void OnSdlGenericEvent(const SDL_Event& sdlEvent);
-#endif
-
-    /**
-    In SDL, this executes all the registered headers
-    */
-    void OnAnimationFrame();
-
-    //void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
-    std::vector<std::pair<OnAnimationFrameFunc, void*> >  
-      animationFrameHandlers_;
-    
-    void OnResize(unsigned int width, unsigned int height);
-
-#if ORTHANC_ENABLE_SDL == 1
-    template<typename Func>
-    struct EventHandlerData
-    {
-      EventHandlerData(std::string canvasName, Func func, void* userData) 
-        : canvasName(canvasName)
-        , func(func)
-        , userData(userData)
-      {
-      }
-
-      std::string canvasName;
-      Func        func;
-      void*       userData;
-    };
-    std::vector<EventHandlerData<OnSdlWindowResizeFunc> > resizeHandlers_;
-    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseDownHandlers_;
-    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseDblCickHandlers_;
-    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseMoveHandlers_;
-    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseUpHandlers_;
-    std::vector<EventHandlerData<OnMouseWheelFunc  > >    mouseWheelHandlers_;
-    std::vector<EventHandlerData<OnKeyDownFunc > >        keyDownHandlers_;
-    std::vector<EventHandlerData<OnKeyUpFunc > >          keyUpHandlers_;
-    std::vector<EventHandlerData<OnSdlEventCallback > >   sdlEventHandlers_;
-
-    /**
-    This executes all the registered headers if needed (in wasm, the browser
-    deals with this)
-    */
-    void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event);
-
-    void OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event);
-
-    /**
-    Same remark as OnMouseEvent
-    */
-    void OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event);
-
-#endif
-
-    /**
-    This executes all the registered headers if needed (in wasm, the browser
-    deals with this)
-    */
-    void ViewportsUpdateSize();
-  };
-}
--- a/Applications/Generic/NativeStoneApplicationContext.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "NativeStoneApplicationContext.h"
-#include "../../Platforms/Generic/OracleWebService.h"
-
-namespace OrthancStone
-{
-  void NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(
-    boost::shared_ptr<Deprecated::IWidget> widget)
-  {
-    that_.centralViewport_.SetCentralWidget(widget);
-  }
-
-
-  void NativeStoneApplicationContext::UpdateThread(NativeStoneApplicationContext* that)
-  {
-    while (!that->stopped_)
-    {
-      {
-        GlobalMutexLocker locker(*that);
-        locker.GetCentralViewport().DoAnimation();
-      }
-      
-      boost::this_thread::sleep(boost::posix_time::milliseconds(that->updateDelayInMs_));
-    }
-  }
-  
-
-  NativeStoneApplicationContext::NativeStoneApplicationContext() :
-    stopped_(true),
-    updateDelayInMs_(100)   // By default, 100ms between each refresh of the content
-  {
-    srand(static_cast<unsigned int>(time(NULL))); 
-  }
-
-
-  void NativeStoneApplicationContext::Start()
-  {
-    boost::recursive_mutex::scoped_lock lock(globalMutex_);
-    
-    if (stopped_ &&
-        centralViewport_.HasAnimation())
-    {
-      stopped_ = false;
-      updateThread_ = boost::thread(UpdateThread, this);
-    }
-  }
-
-
-  void NativeStoneApplicationContext::Stop()
-  {
-    stopped_ = true;
-    
-    if (updateThread_.joinable())
-    {
-      updateThread_.join();
-    }
-  }
-}
--- a/Applications/Generic/NativeStoneApplicationContext.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../../Framework/Deprecated/Viewport/WidgetViewport.h"
-#include "../../Framework/Deprecated/Volumes/ISlicedVolume.h"
-#include "../../Framework/Deprecated/Volumes/IVolumeLoader.h"
-
-#include <list>
-#include <boost/thread.hpp>
-#include "../StoneApplicationContext.h"
-
-namespace OrthancStone
-{
-  class NativeStoneApplicationContext : public StoneApplicationContext
-  {
-  private:
-    static void UpdateThread(NativeStoneApplicationContext* that);
-
-    boost::recursive_mutex    globalMutex_;
-    Deprecated::WidgetViewport  centralViewport_;
-    boost::thread   updateThread_;
-    bool            stopped_;
-    unsigned int    updateDelayInMs_;
-
-  public:
-    class GlobalMutexLocker: public boost::noncopyable
-    {
-    private:
-      NativeStoneApplicationContext&        that_;
-      boost::recursive_mutex::scoped_lock   lock_;
-      
-    public:
-      GlobalMutexLocker(NativeStoneApplicationContext& that) :
-        that_(that),
-        lock_(that.globalMutex_)
-      {
-      }
-
-      void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget);
-
-      Deprecated::IViewport& GetCentralViewport() 
-      {
-        return that_.centralViewport_;
-      }
-
-      void SetUpdateDelay(unsigned int delayInMs)
-      {
-        that_.updateDelayInMs_ = delayInMs;
-      }
-    };
-
-    NativeStoneApplicationContext();
-
-    void Start();
-
-    void Stop();
-  };
-}
--- a/Applications/Generic/NativeStoneApplicationRunner.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#if ORTHANC_ENABLE_THREADS != 1
-#error this file shall be included only with the ORTHANC_ENABLE_THREADS set to 1
-#endif
-
-#include "NativeStoneApplicationRunner.h"
-
-#include "../../Framework/Deprecated/Toolbox/MessagingToolbox.h"
-#include "../../Platforms/Generic/OracleWebService.h"
-#include "../../Platforms/Generic/OracleDelayedCallExecutor.h"
-#include "NativeStoneApplicationContext.h"
-
-#include <Core/Logging.h>
-#include <Core/HttpClient.h>
-#include <Core/Toolbox.h>
-#include <Core/OrthancException.h>
-#include <Plugins/Samples/Common/OrthancHttpConnection.h>
-
-#include <boost/program_options.hpp>
-
-namespace OrthancStone
-{
-  // Anonymous namespace to avoid clashes against other compilation modules
-  namespace
-  {
-    class LogStatusBar : public Deprecated::IStatusBar
-    {
-    public:
-      virtual void ClearMessage()
-      {
-      }
-
-      virtual void SetMessage(const std::string& message)
-      {
-        LOG(WARNING) << message;
-      }
-    };
-  }
-
-  int NativeStoneApplicationRunner::Execute(int argc,
-                                            char* argv[])
-  {
-    /******************************************************************
-     * Initialize all the subcomponents of Orthanc Stone
-     ******************************************************************/
-
-    Orthanc::Logging::Initialize();
-    Orthanc::Toolbox::InitializeOpenSsl();
-    Orthanc::HttpClient::GlobalInitialize();
-
-    Initialize();
-
-    /******************************************************************
-     * Declare and parse the command-line options of the application
-     ******************************************************************/
-
-    boost::program_options::options_description options;
-
-    { // generic options
-      boost::program_options::options_description generic("Generic options");
-      generic.add_options()
-          ("help", "Display this help and exit")
-          ("verbose", "Be verbose in logs")
-          ("orthanc", boost::program_options::value<std::string>()->
-            default_value("http://localhost:8042/"),
-           "URL to the Orthanc server")
-          ("username", "Username for the Orthanc server")
-          ("password", "Password for the Orthanc server")
-          ("https-verify", boost::program_options::value<bool>()->
-            default_value(true), "Check HTTPS certificates")
-          ;
-
-      options.add(generic);
-    }
-
-    // platform specific options
-    DeclareCommandLineOptions(options);
-    
-    // application specific options
-    application_->DeclareStartupOptions(options);
-
-    boost::program_options::variables_map parameters;
-    bool error = false;
-
-    try
-    {
-      boost::program_options::store(
-        boost::program_options::command_line_parser(argc, argv).
-          options(options).allow_unregistered().run(), parameters);
-      boost::program_options::notify(parameters);
-    }
-    catch (boost::program_options::error& e)
-    {
-      LOG(ERROR) << 
-        "Error while parsing the command-line arguments: " << e.what();
-      error = true;
-    }
-
-
-    /******************************************************************
-     * Configure the application with the command-line parameters
-     ******************************************************************/
-
-    if (error || parameters.count("help"))
-    {
-      std::cout << std::endl;
-
-      std::cout << options << "\n";
-      return error ? -1 : 0;
-    }
-
-    if (parameters.count("https-verify") &&
-        !parameters["https-verify"].as<bool>())
-    {
-      LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)";
-      Orthanc::HttpClient::ConfigureSsl(false, "");
-    }
-
-    LOG(ERROR) << "???????? if (parameters.count(\"verbose\"))";
-    if (parameters.count("verbose"))
-    {
-      LOG(ERROR) << "parameters.count(\"verbose\") != 0";
-      Orthanc::Logging::EnableInfoLevel(true);
-      LOG(INFO) << "Verbose logs are enabled";
-    }
-
-    LOG(ERROR) << "???????? if (parameters.count(\"trace\"))";
-    if (parameters.count("trace"))
-    {
-      LOG(ERROR) << "parameters.count(\"trace\") != 0";
-      Orthanc::Logging::EnableTraceLevel(true);
-      VLOG(1) << "Trace logs are enabled";
-    }
-
-    ParseCommandLineOptions(parameters);
-
-    bool success = true;
-    try
-    {
-      /****************************************************************
-       * Initialize the connection to the Orthanc server
-       ****************************************************************/
-
-      Orthanc::WebServiceParameters webServiceParameters;
-
-      if (parameters.count("orthanc"))
-      {
-        webServiceParameters.SetUrl(parameters["orthanc"].as<std::string>());
-      }
-
-      if (parameters.count("username") && parameters.count("password"))
-      {
-        webServiceParameters.SetCredentials(parameters["username"].
-          as<std::string>(),
-          parameters["password"].as<std::string>());
-      }
-
-      LOG(WARNING) << "URL to the Orthanc REST API: " << 
-        webServiceParameters.GetUrl();
-
-      {
-        OrthancPlugins::OrthancHttpConnection orthanc(webServiceParameters);
-        if (!Deprecated::MessagingToolbox::CheckOrthancVersion(orthanc))
-        {
-          LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of "
-            << "Orthanc, please upgrade";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
-        }
-      }
-
-
-      /****************************************************************
-       * Initialize the application
-       ****************************************************************/
-
-      LOG(WARNING) << "Creating the widgets of the application";
-
-      LogStatusBar statusBar;
-
-      NativeStoneApplicationContext context;
-
-      {
-        // use multiple threads to execute asynchronous tasks like 
-        // download content
-        Deprecated::Oracle oracle(6); 
-        oracle.Start();
-
-        {
-          boost::shared_ptr<Deprecated::OracleWebService> webService
-            (new Deprecated::OracleWebService(oracle, webServiceParameters, context));
-          context.SetWebService(webService);
-          context.SetOrthancBaseUrl(webServiceParameters.GetUrl());
-
-          Deprecated::OracleDelayedCallExecutor delayedExecutor(oracle, context);
-          context.SetDelayedCallExecutor(delayedExecutor);
-
-          application_->Initialize(&context, statusBar, parameters);
-
-          {
-            NativeStoneApplicationContext::GlobalMutexLocker locker(context);
-            locker.SetCentralWidget(application_->GetCentralWidget());
-            locker.GetCentralViewport().SetStatusBar(statusBar);
-          }
-
-          std::string title = application_->GetTitle();
-          if (title.empty())
-          {
-            title = "Stone of Orthanc";
-          }
-
-          /****************************************************************
-           * Run the application
-           ****************************************************************/
-
-          Run(context, title, argc, argv);
-
-          /****************************************************************
-           * Finalize the application
-           ****************************************************************/
-
-          oracle.Stop();
-        }
-      }
-
-      LOG(WARNING) << "The application is stopping";
-      application_->Finalize();
-    }
-    catch (Orthanc::OrthancException& e)
-    {
-      LOG(ERROR) << "EXCEPTION: " << e.What();
-      success = false;
-    }
-
-
-    /******************************************************************
-     * Finalize all the subcomponents of Orthanc Stone
-     ******************************************************************/
-
-    Finalize();
-    Orthanc::HttpClient::GlobalFinalize();
-    Orthanc::Toolbox::FinalizeOpenSsl();
-
-    return (success ? 0 : -1);
-  }
-}
--- a/Applications/Generic/NativeStoneApplicationRunner.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../IStoneApplication.h"
-
-#if ORTHANC_ENABLE_THREADS != 1
-#error this file shall be included only with the ORTHANC_ENABLE_THREADS set to 1
-#endif
-
-namespace OrthancStone
-{
-  class NativeStoneApplicationContext;
-
-  class NativeStoneApplicationRunner
-  {
-  protected:
-    boost::shared_ptr<IStoneApplication>  application_;
-    
-  public:
-    NativeStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application)
-      : application_(application)
-    {
-    }
-    int Execute(int argc,
-                char* argv[]);
-
-    virtual void Initialize() = 0;
-    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0;
-    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) = 0;
-
-    virtual void Run(NativeStoneApplicationContext& context, const std::string& title, int argc, char* argv[]) = 0;
-    virtual void Finalize() = 0;
-  };
-
-}
--- a/Applications/Generic/Scene2DInteractor.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-#pragma once
-
-#include "../../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/Applications/IStoneApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "StoneApplicationContext.h"
-#include "../Framework/Deprecated/Viewport/WidgetViewport.h"
-
-#include <boost/program_options.hpp>
-#include <json/json.h>
-
-namespace OrthancStone
-{
-#if ORTHANC_ENABLE_QT==1
-  class QStoneMainWindow;
-#endif
-
-  // a StoneApplication is an application that can actually be executed
-  // in multiple environments.  i.e: it can run natively integrated in a QtApplication
-  // or it can be executed as part of a WebPage when compiled into WebAssembly.
-  class IStoneApplication : public boost::noncopyable
-  {
-  protected:
-    StoneApplicationContext* context_;
-
-  public:
-    virtual ~IStoneApplication()
-    {
-    }
-
-    virtual void DeclareStartupOptions(boost::program_options::options_description& options) = 0;
-    virtual void Initialize(StoneApplicationContext* context,
-                            Deprecated::IStatusBar& statusBar,
-                            const boost::program_options::variables_map& parameters) = 0;
-
-    /**
-      This method is meant to process messages received from the outside world (i.e. GUI)
-    */
-    virtual void HandleSerializedMessage(const char* data) = 0;
-
-#if ORTHANC_ENABLE_WASM==1
-    virtual void InitializeWasm() {}  // specific initialization when the app is running in WebAssembly.  This is called after the other Initialize()
-#endif
-#if ORTHANC_ENABLE_QT==1
-      virtual QStoneMainWindow* CreateQtMainWindow() = 0;
-#endif
-
-    virtual std::string GetTitle() const = 0;
-    
-    virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) = 0;
-    
-    virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() = 0;
-    
-    virtual void Finalize() = 0;
-  };
-}
--- a/Applications/Qt/QCairoWidget.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "QCairoWidget.h"
-
-#include <QPainter>
-#include <QPaintEvent>
-
-#include <stdexcept>
-
-
-QCairoWidget::StoneObserver::StoneObserver(QCairoWidget& that,
-                                           Deprecated::IViewport& viewport,
-                                           OrthancStone::MessageBroker& broker) :
-  OrthancStone::IObserver(broker),
-  that_(that)
-{
-  // get notified each time the content of the central viewport changes
-  viewport.RegisterObserverCallback(
-    new OrthancStone::Callable<StoneObserver, Deprecated::IViewport::ViewportChangedMessage>
-    (*this, &StoneObserver::OnViewportChanged));
-}
-
-
-QCairoWidget::QCairoWidget(QWidget *parent) :
-  QWidget(parent),
-  context_(NULL)
-{
-  setFocusPolicy(Qt::StrongFocus); // catch keyPressEvents
-}
-
-
-void QCairoWidget::SetContext(OrthancStone::NativeStoneApplicationContext& context)
-{
-  context_ = &context;
-
-  {
-    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-    observer_.reset(new StoneObserver(*this,
-                                      locker.GetCentralViewport(),
-                                      locker.GetMessageBroker()));
-  }
-}
-
-
-void QCairoWidget::paintEvent(QPaintEvent* /*event*/)
-{
-  QPainter painter(this);
-
-  if (image_.get() != NULL &&
-      context_ != NULL)
-  {
-    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-    Deprecated::IViewport& viewport = locker.GetCentralViewport();
-    Orthanc::ImageAccessor a;
-    surface_.GetWriteableAccessor(a);
-    viewport.Render(a);
-    painter.drawImage(0, 0, *image_);
-  }
-  else
-  {
-    painter.fillRect(rect(), Qt::red);
-  }
-}
-
-OrthancStone::KeyboardModifiers GetKeyboardModifiers(QInputEvent* event)
-{
-  Qt::KeyboardModifiers qtModifiers = event->modifiers();
-  int stoneModifiers = static_cast<int>(OrthancStone::KeyboardModifiers_None);
-  if ((qtModifiers & Qt::AltModifier) != 0)
-  {
-    stoneModifiers |= static_cast<int>(OrthancStone::KeyboardModifiers_Alt);
-  }
-  if ((qtModifiers & Qt::ControlModifier) != 0)
-  {
-    stoneModifiers |= static_cast<int>(OrthancStone::KeyboardModifiers_Control);
-  }
-  if ((qtModifiers & Qt::ShiftModifier) != 0)
-  {
-    stoneModifiers |= static_cast<int>(OrthancStone::KeyboardModifiers_Shift);
-  }
-  return static_cast<OrthancStone::KeyboardModifiers>(stoneModifiers);
-}
-
-void QCairoWidget::mousePressEvent(QMouseEvent* event)
-{
-  OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
-
-  OrthancStone::MouseButton button;
-
-  switch (event->button())
-  {
-    case Qt::LeftButton:
-      button = OrthancStone::MouseButton_Left;
-      break;
-
-    case Qt::RightButton:
-      button = OrthancStone::MouseButton_Right;
-      break;
-
-    case Qt::MiddleButton:
-      button = OrthancStone::MouseButton_Middle;
-      break;
-
-    default:
-      return;  // Unsupported button
-  }
-
-  {
-    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-    locker.GetCentralViewport().MouseDown(button, event->pos().x(), event->pos().y(), stoneModifiers, std::vector<Deprecated::Touch>());
-  }
-}
-
-
-void QCairoWidget::mouseReleaseEvent(QMouseEvent* /*eventNotUsed*/)
-{
-  OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-  locker.GetCentralViewport().MouseLeave();
-}
-
-
-void QCairoWidget::mouseMoveEvent(QMouseEvent* event)
-{
-  OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-  locker.GetCentralViewport().MouseMove(event->pos().x(), event->pos().y(), std::vector<Deprecated::Touch>());
-}
-
-
-void QCairoWidget::wheelEvent(QWheelEvent * event)
-{
-  OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-
-  OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
-
-  if (event->orientation() == Qt::Vertical)
-  {
-    if (event->delta() < 0)  // TODO: compare direction with SDL and make sure we send the same directions
-    {
-       locker.GetCentralViewport().MouseWheel(OrthancStone::MouseWheelDirection_Up, event->pos().x(), event->pos().y(), stoneModifiers);
-    }
-    else
-    {
-      locker.GetCentralViewport().MouseWheel(OrthancStone::MouseWheelDirection_Down, event->pos().x(), event->pos().y(), stoneModifiers);
-    }
-  }
-}
-
-void QCairoWidget::keyPressEvent(QKeyEvent *event)
-{
-  using namespace OrthancStone;
-
-  OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
-
-  OrthancStone::KeyboardKeys keyType = OrthancStone::KeyboardKeys_Generic;
-  char keyChar = event->text()[0].toLatin1();
-
-#define CASE_QT_KEY_TO_ORTHANC(qt, o) case qt: keyType = o; break;
-  if (keyChar == 0)
-  {
-    switch (event->key())
-    {
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Up, KeyboardKeys_Up);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Down, KeyboardKeys_Down);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Left, KeyboardKeys_Left);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Right, KeyboardKeys_Right);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F1, KeyboardKeys_F1);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F2, KeyboardKeys_F2);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F3, KeyboardKeys_F3);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F4, KeyboardKeys_F4);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F5, KeyboardKeys_F5);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F6, KeyboardKeys_F6);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F7, KeyboardKeys_F7);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F8, KeyboardKeys_F8);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F9, KeyboardKeys_F9);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F10, KeyboardKeys_F10);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F11, KeyboardKeys_F11);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F12, KeyboardKeys_F12);
-    default:
-      break;
-    }
-  }
-  else if (keyChar == 127)
-  {
-    switch (event->key())
-    {
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Delete, KeyboardKeys_Delete);
-      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Backspace, KeyboardKeys_Backspace);
-    default:
-      break;
-    }
-  }
-
-  {
-    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);    
-    locker.GetCentralViewport().KeyPressed(keyType, keyChar, stoneModifiers);
-  }
-}
-
-
-void QCairoWidget::resizeEvent(QResizeEvent* event)
-{
-  grabGesture(Qt::PanGesture);
-  QWidget::resizeEvent(event);
-
-  if (event)
-  {
-    surface_.SetSize(event->size().width(), event->size().height(), true);
-
-    image_.reset(new QImage(reinterpret_cast<uchar*>(surface_.GetBuffer()),
-                            event->size().width(), 
-                            event->size().height(),
-                            surface_.GetPitch(),
-                            QImage::Format_RGB32));
-
-    {
-      OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
-      locker.GetCentralViewport().SetSize(event->size().width(), event->size().height());
-    }
-  }
-}
--- a/Applications/Qt/QCairoWidget.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
-4 * 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/NativeStoneApplicationContext.h"
-#include "../../Framework/Wrappers/CairoSurface.h"
-#include "../../Framework/Deprecated/Widgets/IWidget.h"
-
-#include <QWidget>
-#include <memory>
-#include <cassert>
-
-class QCairoWidget : public QWidget
-{
-  Q_OBJECT
-
-private:
-  class StoneObserver : public OrthancStone::IObserver
-  {
-  private:
-    QCairoWidget& that_;
-    
-  public:
-    StoneObserver(QCairoWidget& that,
-                  Deprecated::IViewport& viewport,
-                  OrthancStone::MessageBroker& broker);
-
-    void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
-    {
-      that_.OnViewportChanged();
-    }
-  };
-  
-  std::unique_ptr<QImage>         image_;
-  OrthancStone::CairoSurface    surface_;
-  OrthancStone::NativeStoneApplicationContext* context_;
-  std::unique_ptr<StoneObserver>  observer_;
-
-protected:
-  virtual void paintEvent(QPaintEvent *event);
-
-  virtual void resizeEvent(QResizeEvent *event);
-
-  virtual void mouseMoveEvent(QMouseEvent *event);
-
-  virtual void mousePressEvent(QMouseEvent *event);
-
-  virtual void mouseReleaseEvent(QMouseEvent *event);
-
-  virtual void wheelEvent(QWheelEvent *event);
-
-  virtual void keyPressEvent(QKeyEvent *event);
-
-public:
-  explicit QCairoWidget(QWidget *parent);
- 
-  void SetContext(OrthancStone::NativeStoneApplicationContext& context);
-
-  void OnViewportChanged()
-  {
-    update();  // schedule a repaint (handled by Qt)
-    emit ContentChanged();
-  }
-
-signals:
-  void ContentChanged();
-                                               
-public slots:
-
-};
--- a/Applications/Qt/QStoneMainWindow.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "QStoneMainWindow.h"
-
-namespace OrthancStone
-{
-
-  QStoneMainWindow::QStoneMainWindow(NativeStoneApplicationContext& context,
-                                     QWidget *parent) :
-    QMainWindow(parent),
-    context_(context),
-    cairoCentralWidget_(NULL)
-  {
-  }
-
-  void QStoneMainWindow::SetCentralStoneWidget(QCairoWidget& centralWidget)
-  {
-    cairoCentralWidget_ = &centralWidget;
-    cairoCentralWidget_->SetContext(context_);
-  }
-
-  QStoneMainWindow::~QStoneMainWindow()
-  {
-  }
-}
--- a/Applications/Qt/QStoneMainWindow.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-#pragma once
-
-#include <QMainWindow>
-
-#include "QCairoWidget.h"
-#include "../Generic/NativeStoneApplicationContext.h"
-
-namespace OrthancStone
-{
-  class QStoneMainWindow : public QMainWindow
-  {
-    Q_OBJECT
-
-  private:
-    OrthancStone::NativeStoneApplicationContext& context_;
-    QCairoWidget          *cairoCentralWidget_;
-
-  protected:  // you must inherit this class
-    QStoneMainWindow(NativeStoneApplicationContext& context, QWidget *parent = 0);
-    void SetCentralStoneWidget(QCairoWidget& centralWidget);
-
-  public:
-    virtual ~QStoneMainWindow();
-  };
-
-}
--- a/Applications/Qt/QtStoneApplicationRunner.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#if ORTHANC_ENABLE_QT != 1
-#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
-#endif
-
-#include "QtStoneApplicationRunner.h"
-#include <boost/program_options.hpp>
-#include <QApplication>
-
-#include "../../Framework/Deprecated/Toolbox/MessagingToolbox.h"
-
-#include <Core/Logging.h>
-#include <Core/HttpClient.h>
-#include <Core/Toolbox.h>
-#include <Plugins/Samples/Common/OrthancHttpConnection.h>
-#include "../../Platforms/Generic/OracleWebService.h"
-
-
-namespace OrthancStone
-{
-  void QtStoneApplicationRunner::Initialize()
-  {
-  }
-
-  void QtStoneApplicationRunner::DeclareCommandLineOptions(boost::program_options::options_description& options)
-  {
-  }
-
-  void QtStoneApplicationRunner::Run(NativeStoneApplicationContext& context, const std::string& title, int argc, char* argv[])
-  {
-    context.Start();
-
-    QApplication qtApplication(argc, argv);
-    window_.reset(application_.CreateQtMainWindow());
-
-    window_->show();
-    qtApplication.exec();
-
-    context.Stop();
-  }
-
-  void QtStoneApplicationRunner::Finalize()
-  {
-  }
-
-
-}
--- a/Applications/Qt/QtStoneApplicationRunner.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../Generic/NativeStoneApplicationRunner.h"
-#include "QStoneMainWindow.h"
-
-#if ORTHANC_ENABLE_QT != 1
-#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
-#endif
-
-namespace OrthancStone
-{
-  class QtStoneApplicationRunner : public NativeStoneApplicationRunner
-  {
-  protected:
-    std::unique_ptr<QStoneMainWindow> window_;
-
-  public:
-    QtStoneApplicationRunner(MessageBroker& broker,
-                             IStoneApplication& application)
-      : NativeStoneApplicationRunner(broker, application)
-    {
-    }
-
-
-    virtual void Initialize();
-
-    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
-    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) {}
-    virtual void Run(NativeStoneApplicationContext& context, const std::string& title, int argc, char* argv[]);
-    virtual void Finalize();
-  };
-
-}
--- a/Applications/Samples/Deprecated/BasicPetCtFusionApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleInteractor.h"
-
-#include <Core/Logging.h>
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class BasicPetCtFusionApplication : public SampleApplicationBase
-    {
-    private:
-      class Interactor : public SampleInteractor
-      {
-      public:
-        static void SetStyle(LayeredSceneWidget& widget,
-                             bool ct,
-                             bool pet)
-        {
-          if (ct)
-          {
-            RenderStyle style;
-            style.windowing_ = ImageWindowing_Bone;
-            widget.SetLayerStyle(0, style);
-          }
-          else
-          {
-            RenderStyle style;
-            style.visible_ = false;
-            widget.SetLayerStyle(0, style);
-          }
-
-          if (ct && pet)
-          {
-            RenderStyle style;
-            style.applyLut_ = true;
-            style.alpha_ = 0.5;
-            widget.SetLayerStyle(1, style);
-          }
-          else if (pet)
-          {
-            RenderStyle style;
-            style.applyLut_ = true;
-            widget.SetLayerStyle(1, style);
-          }
-          else
-          {
-            RenderStyle style;
-            style.visible_ = false;
-            widget.SetLayerStyle(1, style);
-          }
-        }
-
-
-        static bool IsVisible(LayeredSceneWidget& widget,
-                              size_t layer)
-        {
-          RenderStyle style = widget.GetLayerStyle(layer);
-          return style.visible_;
-        }
-
-
-        static void ToggleInterpolation(LayeredSceneWidget& widget,
-                                        size_t layer)
-        {
-          RenderStyle style = widget.GetLayerStyle(layer);
-         
-          if (style.interpolation_ == ImageInterpolation_Bilinear)
-          {
-            style.interpolation_ = ImageInterpolation_Nearest;
-          }
-          else
-          {
-            style.interpolation_ = ImageInterpolation_Bilinear;
-          }
-
-          widget.SetLayerStyle(layer, style);
-        }
-
-
-        Interactor(VolumeImage& volume,
-                   VolumeProjection projection, 
-                   bool reverse) :
-          SampleInteractor(volume, projection, reverse)
-        {
-        }
-
-
-        virtual void KeyPressed(WorldSceneWidget& widget,
-                                char key,
-                                KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
-        {
-          LayeredSceneWidget& layered = dynamic_cast<LayeredSceneWidget&>(widget);
-
-          switch (key)
-          {
-            case 'c':
-              // Toggle the visibility of the CT layer
-              SetStyle(layered, !IsVisible(layered, 0), IsVisible(layered, 1));
-              break;
-
-            case 'p':
-              // Toggle the visibility of the PET layer
-              SetStyle(layered, IsVisible(layered, 0), !IsVisible(layered, 1));
-              break;
-
-            case 'i':
-            {
-              // Toggle on/off the interpolation
-              ToggleInterpolation(layered, 0);
-              ToggleInterpolation(layered, 1);
-              break;
-            }
-
-            default:
-              break;
-          }
-        }
-      };
-
-
-    public:
-      virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("ct", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the CT series")
-          ("pet", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the PET series")
-          ("threads", boost::program_options::value<unsigned int>()->default_value(3), 
-           "Number of download threads for the CT series")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(BasicApplicationContext& context,
-                              IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        if (parameters.count("ct") != 1 ||
-            parameters.count("pet") != 1)
-        {
-          LOG(ERROR) << "The series ID is missing";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::string ct = parameters["ct"].as<std::string>();
-        std::string pet = parameters["pet"].as<std::string>();
-        unsigned int threads = parameters["threads"].as<unsigned int>();
-
-        VolumeImage& ctVolume = context.AddSeriesVolume(ct, true /* progressive download */, threads);
-        VolumeImage& petVolume = context.AddSeriesVolume(pet, true /* progressive download */, 1);
-
-        // Take the PET volume as the reference for the slices
-        std::unique_ptr<Interactor> interactor(new Interactor(petVolume, VolumeProjection_Axial, false /* don't reverse normal */));
-
-        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
-        widget->AddLayer(new VolumeImage::LayerFactory(ctVolume));
-        widget->AddLayer(new VolumeImage::LayerFactory(petVolume));
-        widget->SetSlice(interactor->GetCursor().GetCurrentSlice());
-        widget->SetInteractor(*interactor);
-
-        Interactor::SetStyle(*widget, true, true);   // Initially, show both CT and PET layers
-
-        context.AddInteractor(interactor.release());
-        context.SetCentralWidget(widget.release());
-
-        statusBar.SetMessage("Use the key \"t\" to toggle the fullscreen mode");
-        statusBar.SetMessage("Use the key \"c\" to show/hide the CT layer");
-        statusBar.SetMessage("Use the key \"p\" to show/hide the PET layer");
-        statusBar.SetMessage("Use the key \"i\" to toggle the smoothing of the images");
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/CMakeLists.txt	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,292 +0,0 @@
-# Usage (Linux):
-# to build the WASM samples
-# source ~/Downloads/emsdk/emsdk_env.sh && cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
-# to build the Qt samples
-
-cmake_minimum_required(VERSION 2.8.3)
-project(OrthancStone)
-
-include(../../../Resources/CMake/OrthancStoneParameters.cmake)
-
-set(ENABLE_STONE_DEPRECATED ON)  # Need deprecated classes for these samples
-set(EMSCRIPTEN_SET_LLVM_WASM_BACKEND ON)
-
-include(${ORTHANC_ROOT}/Resources/CMake/DownloadPackage.cmake)
-DownloadPackage(
-  "a24b8136b8f3bb93f166baf97d9328de"
-  "http://orthanc.osimis.io/ThirdPartyDownloads/ubuntu-font-family-0.83.zip"
-  "${CMAKE_BINARY_DIR}/ubuntu-font-family-0.83")
-
-set(ORTHANC_STONE_APPLICATION_RESOURCES
-  UBUNTU_FONT  ${CMAKE_BINARY_DIR}/ubuntu-font-family-0.83/Ubuntu-R.ttf
-  )
-
-if (OPENSSL_NO_CAPIENG)
-add_definitions(-DOPENSSL_NO_CAPIENG=1)
-endif()
-
-
-# the following block has been borrowed from orthanc/**/Compiler.cmake
-if (MSVC_MULTIPLE_PROCESSES)
-# "If you omit the processMax argument in the /MP option, the
-# compiler obtains the number of effective processors from the
-# operating system, and then creates one process per effective
-# processor"
-# https://blog.kitware.com/cmake-building-with-all-your-cores/
-# https://docs.microsoft.com/en-us/cpp/build/reference/mp-build-with-multiple-processes
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
-endif()
-
-#set(ENABLE_DCMTK ON)
-
-set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
-set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
-set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
-
-if (ENABLE_WASM)
-  #####################################################################
-  ## Configuration of the Emscripten compiler for WebAssembly target
-  #####################################################################
-
-  set(WASM_FLAGS "-s WASM=1")
-  set(WASM_FLAGS "${WASM_FLAGS} -s STRICT=1") # drops support for all deprecated build options
-  set(WASM_FLAGS "${WASM_FLAGS} -s FILESYSTEM=1") # if we don't include it, gen_uuid.c fails to build because srand, getpid(), ... are not defined
-  set(WASM_FLAGS "${WASM_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0") # actually enable exception catching 
-  set(WASM_FLAGS "${WASM_FLAGS} -s ERROR_ON_MISSING_LIBRARIES=1")
-  
-  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
-    set(WASM_FLAGS "${WASM_FLAGS} -g4") # generate debug information
-    set(WASM_FLAGS "${WASM_FLAGS} -s ASSERTIONS=2") # more runtime checks
-  else()
-    set(WASM_FLAGS "${WASM_FLAGS} -Os") # optimize for web (speed and size)
-  endif()
-
-  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
-
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
-
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_FLAGS}")  # not always clear which flags are for the compiler and which one are for the linker -> pass them all to the linker too
-  # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"'")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=128000000")
-
-  add_definitions(-DORTHANC_ENABLE_WASM=1)
-  set(ORTHANC_SANDBOXED ON)
-
-elseif (ENABLE_QT OR ENABLE_SDL)
-
-  set(ENABLE_NATIVE ON)
-  set(ORTHANC_SANDBOXED OFF)
-  set(ENABLE_CRYPTO_OPTIONS ON)
-  set(ENABLE_GOOGLE_TEST ON)
-  set(ENABLE_WEB_CLIENT ON)
-
-else()
-  set(ENABLE_NATIVE ON)
-  set(ENABLE_OPENGL OFF)
-  
-endif()
-
-
-#####################################################################
-## Configuration for Orthanc
-#####################################################################
-
-# include(../../Resources/CMake/Version.cmake)
-
-if (ORTHANC_STONE_VERSION STREQUAL "mainline")
-  set(ORTHANC_FRAMEWORK_VERSION "mainline")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
-else()
-  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
-endif()
-
-set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
-set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
-set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
-
-add_definitions(
-  -DORTHANC_ENABLE_LOGGING_PLUGIN=0
-  )
-
-
-#####################################################################
-## Build a static library containing the Orthanc Stone framework
-#####################################################################
-
-
-LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
-
-include(../../../Resources/CMake/OrthancStoneConfiguration.cmake)
-
-add_library(OrthancStone STATIC
-  ${ORTHANC_STONE_SOURCES}
-  )
-
-#####################################################################
-## Build all the sample applications
-#####################################################################
-
-include_directories(${ORTHANC_STONE_ROOT})
-
-# files common to all samples
-list(APPEND SAMPLE_APPLICATIONS_SOURCES
-  ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleInteractor.h
-  ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleApplicationBase.h
-  )
-
-if (ENABLE_QT)
-  list(APPEND SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleQtApplicationRunner.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindow.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.cpp
-    )
-
-  ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindow.ui
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.ui
-    )
-
-  ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
-    ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindow.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.h
-    )
-endif()
-
-if (ENABLE_NATIVE)
-  list(APPEND SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleMainNative.cpp
-    )
-
-elseif (ENABLE_WASM)
-
-  list(APPEND SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleMainWasm.cpp
-    ${STONE_WASM_SOURCES}
-    )
-endif()
-
-
-macro(BuildSingleFileSample Target Header Sample)
-  add_executable(${Target}
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/${Header}
-    ${SAMPLE_APPLICATIONS_SOURCES}
-    )
-  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
-  target_link_libraries(${Target} OrthancStone)
-endmacro()
-
-
-if (ENABLE_SDL)
-  #BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
-  #BuildSingleFileSample(OrthancStoneTestPattern TestPatternApplication.h 2)
-  BuildSingleFileSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
-  #BuildSingleFileSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
-  #BuildSingleFileSample(OrthancStoneBasicPetCtFusion 5)
-  #BuildSingleFileSample(OrthancStoneSynchronizedSeries 6)
-  #BuildSingleFileSample(OrthancStoneLayoutPetCtFusion 7)
-  BuildSingleFileSample(OrthancStoneSimpleViewerSingleFile SimpleViewerApplicationSingleFile.h 8)  # we keep that one just as a sample before we convert another sample to this pattern
-  BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
-endif()
-  
-##### SimpleViewer sample (Qt and WASM only) #######
-
-if (ENABLE_QT OR ENABLE_WASM)
-
-    if (ENABLE_QT)
-      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.cpp
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/mainQt.cpp
-        )
-
-      ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui
-        )
-
-      ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.h
-        )
-
-elseif (ENABLE_WASM)
-        list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
-            ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Wasm/mainWasm.cpp
-            ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp
-            ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.h
-            ${STONE_WASM_SOURCES}
-          )
-    endif()
-
-    add_executable(OrthancStoneSimpleViewer
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/AppStatus.h
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.cpp
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.h
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.cpp
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.h
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.cpp
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.h
-      ${SIMPLE_VIEWER_APPLICATION_SOURCES}
-      )
-    target_link_libraries(OrthancStoneSimpleViewer OrthancStone)
-
-    BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
-endif()
-
-#####################################################################
-## Build the unit tests
-#####################################################################
-
-if (ENABLE_NATIVE)
-  add_executable(UnitTests
-    ${GOOGLE_TEST_SOURCES}
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/GenericToolboxTests.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/ImageToolboxTests.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/PixelTestPatternsTests.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStrategy.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStructureSet.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
-    )
-
-  target_link_libraries(UnitTests OrthancStone)
-
-  add_custom_command(
-    TARGET UnitTests
-    POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy
-      "${ORTHANC_STONE_ROOT}/UnitTestsSources/72c773ac-5059f2c4-2e6a9120-4fd4bca1-45701661.json" 
-      "$<TARGET_FILE_DIR:UnitTests>/72c773ac-5059f2c4-2e6a9120-4fd4bca1-45701661.json"
-    )
-
-endif()
-
-#####################################################################
-## Generate the documentation if Doxygen is present
-#####################################################################
-
-find_package(Doxygen)
-if (DOXYGEN_FOUND)
-  configure_file(
-    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
-    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
-    @ONLY)
-
-  add_custom_target(doc
-    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
-    COMMENT "Generating documentation with Doxygen" VERBATIM
-    )
-else()
-  message("Doxygen not found. The documentation will not be built.")
-endif()
--- a/Applications/Samples/Deprecated/CMakeLists.txt.old	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,248 +0,0 @@
-# Usage: see README file
-
-cmake_minimum_required(VERSION 2.8.3)
-
-# Automatically link Qt executables to qtmain target on Windows
-# ("OLD" == do not link)
-if(POLICY CMP0020)
-  cmake_policy(SET CMP0020 OLD)
-endif()
-
-# Only interpret if() arguments as variables or keywords when unquoted.
-# NEW = do NOT dereference *quoted* variables
-if(POLICY CMP0054)
-  cmake_policy(SET CMP0054 NEW)
-endif()
-
-project(OrthancStone)
-
-include(../../Resources/CMake/OrthancStoneParameters.cmake)
-
-#set(ENABLE_DCMTK ON)
-
-set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
-set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
-set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
-
-# TODO: replace or compute STONE_SOURCES_DIR from CMAKE_CURRENT_LIST_FILE
-
-if (ENABLE_WASM)
-  #####################################################################
-  ## Configuration of the Emscripten compiler for WebAssembly target
-  #####################################################################
-
-  set(WASM_FLAGS "-s WASM=1 -O0 -g0")
-  message("*****************************************************************************")
-  message("WARNING: optimizations are disabled in emcc!!! Enable them for production use")
-  message("*****************************************************************************")
-  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js  -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
-
-  # Handling of memory
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")  # Resize
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")  # 512MB
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=536870912 -s TOTAL_STACK=128000000")  # 512MB + resize
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=1073741824")  # 1GB + resize
-
-  # To debug exceptions
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2")
-
-  add_definitions(-DORTHANC_ENABLE_WASM=1)
-  set(ORTHANC_SANDBOXED ON)
-
-elseif (ENABLE_QT OR ENABLE_SDL)
-
-  set(ENABLE_NATIVE ON)
-  set(ORTHANC_SANDBOXED OFF)
-  set(ENABLE_CRYPTO_OPTIONS ON)
-  set(ENABLE_GOOGLE_TEST ON)
-  set(ENABLE_WEB_CLIENT ON)
-
-endif()
-
-#####################################################################
-## Configuration for Orthanc
-#####################################################################
-
-# include(../../Resources/CMake/Version.cmake)
-
-if (ORTHANC_STONE_VERSION STREQUAL "mainline")
-  set(ORTHANC_FRAMEWORK_VERSION "mainline")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
-else()
-  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
-endif()
-
-set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
-set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
-set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
-
-#####################################################################
-## Build a static library containing the Orthanc Stone framework
-#####################################################################
-
-LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
-
-include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
-
-add_library(OrthancStone STATIC
-  ${ORTHANC_STONE_SOURCES}
-  )
-
-#####################################################################
-## Build all the sample applications
-#####################################################################
-
-include_directories(${ORTHANC_STONE_ROOT})
-
-# files common to all samples
-list(APPEND SAMPLE_APPLICATIONS_SOURCES
-  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
-  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
-  )
-
-if (ENABLE_QT)
-  list(APPEND SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp
-    )
-
-  ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.ui
-    )
-
-  ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
-    ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.h
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.h
-    )
-endif()
-
-if (ENABLE_NATIVE)
-  list(APPEND SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainNative.cpp
-    )
-
-elseif (ENABLE_WASM)
-
-  list(APPEND SAMPLE_APPLICATIONS_SOURCES
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainWasm.cpp
-    ${STONE_WASM_SOURCES}
-    )
-endif()
-
-
-macro(BuildSingleFileSample Target Header Sample)
-  add_executable(${Target}
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header}
-    ${SAMPLE_APPLICATIONS_SOURCES}
-    )
-  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
-  target_link_libraries(${Target} OrthancStone)
-  
-  if (ENABLE_QT AND (CMAKE_SYSTEM_NAME STREQUAL "Windows"))
-    message("(ENABLE_QT and (CMAKE_SYSTEM_NAME matches \"Windows\")) is true")
-    add_custom_command(
-      TARGET ${Target} POST_BUILD
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:${Target}>
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${Target}>
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:${Target}>
-    )
-  endif()
-endmacro()
-
-#BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
-#BuildSingleFileSample(OrthancStoneTestPattern TestPatternApplication.h 2)
-BuildSingleFileSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
-#BuildSingleFileSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
-#BuildSingleFileSample(OrthancStoneBasicPetCtFusion 5)
-#BuildSingleFileSample(OrthancStoneSynchronizedSeries 6)
-#BuildSingleFileSample(OrthancStoneLayoutPetCtFusion 7)
-BuildSingleFileSample(OrthancStoneSimpleViewerSingleFile SimpleViewerApplicationSingleFile.h 8)  # we keep that one just as a sample before we convert another sample to this pattern
-BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
-
-##### SimpleViewer sample (Qt and WASM only) #######
-
-if (ENABLE_QT OR ENABLE_WASM)
-
-      # GenerateCodeFromFlatBufferSchema("${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ApplicationCommands.fbs")
-
-      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES ${FLATC_AUTOGENERATED_SOURCES})
-      message(STATUS "SIMPLE_VIEWER_APPLICATION_SOURCES = ${SIMPLE_VIEWER_APPLICATION_SOURCES}")
-      message(STATUS "FLATC_AUTOGENERATED_SOURCES = ${FLATC_AUTOGENERATED_SOURCES}")
-
-    if (ENABLE_QT)
-      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.cpp
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/mainQt.cpp
-        )
-
-      ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
-        )
-
-      ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES
-        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.h
-        )
-
-elseif (ENABLE_WASM)
-        list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
-            ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/mainWasm.cpp
-            ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp
-            ${STONE_WASM_SOURCES}
-          )
-    endif()
-
-    add_executable(OrthancStoneSimpleViewer
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/AppStatus.h
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Messages.h
-      ${SIMPLE_VIEWER_APPLICATION_SOURCES}
-      )
-    target_link_libraries(OrthancStoneSimpleViewer OrthancStone)
-
-endif()
-
-#####################################################################
-## Build the unit tests
-#####################################################################
-
-if (ENABLE_NATIVE)
-  add_executable(UnitTests
-    ${GOOGLE_TEST_SOURCES}
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestExceptions.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
-    ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
-    )
-
-  target_link_libraries(UnitTests OrthancStone)
-endif()
-
-#####################################################################
-## Generate the documentation if Doxygen is present
-#####################################################################
-
-find_package(Doxygen)
-if (DOXYGEN_FOUND)
-  configure_file(
-    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
-    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
-    @ONLY)
-
-  add_custom_target(doc
-    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
-    COMMENT "Generating documentation with Doxygen" VERBATIM
-    )
-else()
-  message("Doxygen not found. The documentation will not be built.")
-endif()
--- a/Applications/Samples/Deprecated/EmptyApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-
-#include "../../../Framework/Widgets/EmptyWidget.h"
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class EmptyApplication : public SampleApplicationBase
-    {
-    public:
-      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("red", boost::program_options::value<int>()->default_value(255), "Background color: red channel")
-          ("green", boost::program_options::value<int>()->default_value(0), "Background color: green channel")
-          ("blue", boost::program_options::value<int>()->default_value(0), "Background color: blue channel")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        int red = parameters["red"].as<int>();
-        int green = parameters["green"].as<int>();
-        int blue = parameters["blue"].as<int>();
-
-        context_->SetCentralWidget(new EmptyWidget(red, green, blue));
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/LayoutPetCtFusionApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,398 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleInteractor.h"
-
-#include "../../../Framework/Layers/ReferenceLineFactory.h"
-#include "../../../Framework/Layers/DicomStructureSetSlicer.h"
-#include "../../../Framework/Widgets/LayoutWidget.h"
-
-#include <Core/Logging.h>
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class LayoutPetCtFusionApplication : 
-      public SampleApplicationBase,
-      public LayeredSceneWidget::ISliceObserver,
-      public WorldSceneWidget::IWorldObserver
-    {
-    private:
-      class Interactor : public SampleInteractor
-      {
-      private:
-        LayoutPetCtFusionApplication& that_;
-
-      public:
-        Interactor(LayoutPetCtFusionApplication& that,
-                   VolumeImage& volume,
-                   VolumeProjection projection, 
-                   bool reverse) :
-          SampleInteractor(volume, projection, reverse),
-          that_(that)
-        {
-        }
-
-        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                            const SliceGeometry& slice,
-                                                            const ViewportGeometry& view,
-                                                            MouseButton button,
-                                                            double x,
-                                                            double y,
-                                                            IStatusBar* statusBar)
-        {
-          if (button == MouseButton_Left)
-          {
-            // Center the sibling views over the clicked point
-            Vector p = slice.MapSliceToWorldCoordinates(x, y);
-
-            if (statusBar != NULL)
-            {
-              char buf[64];
-              sprintf(buf, "Click on coordinates (%.02f,%.02f,%.02f) in cm", p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
-              statusBar->SetMessage(buf);
-            }
-
-            that_.interactorAxial_->LookupSliceContainingPoint(*that_.ctAxial_, p);
-            that_.interactorCoronal_->LookupSliceContainingPoint(*that_.ctCoronal_, p);
-            that_.interactorSagittal_->LookupSliceContainingPoint(*that_.ctSagittal_, p);
-          }
-
-          return NULL;
-        }
-
-        virtual void KeyPressed(WorldSceneWidget& widget,
-                                char key,
-                                KeyboardModifiers modifiers,
-                                IStatusBar* statusBar)
-        {
-          if (key == 's')
-          {
-            that_.FitContent();
-          }
-        }
-      };
-
-      bool                 processingEvent_;
-      Interactor*          interactorAxial_;
-      Interactor*          interactorCoronal_;
-      Interactor*          interactorSagittal_;
-      LayeredSceneWidget*  ctAxial_;
-      LayeredSceneWidget*  ctCoronal_;
-      LayeredSceneWidget*  ctSagittal_;
-      LayeredSceneWidget*  petAxial_;
-      LayeredSceneWidget*  petCoronal_;
-      LayeredSceneWidget*  petSagittal_;
-      LayeredSceneWidget*  fusionAxial_;
-      LayeredSceneWidget*  fusionCoronal_;
-      LayeredSceneWidget*  fusionSagittal_;
-
-
-      void FitContent()
-      {
-        petAxial_->FitContent();
-        petCoronal_->FitContent();
-        petSagittal_->FitContent();
-      }
-
-
-      void AddLayer(LayeredSceneWidget& widget,
-                    VolumeImage& volume,
-                    bool isCt)
-      {
-        size_t layer;
-        widget.AddLayer(layer, new VolumeImage::LayerFactory(volume));
-
-        if (isCt)
-        {
-          RenderStyle style; 
-          style.windowing_ = ImageWindowing_Bone;
-          widget.SetLayerStyle(layer, style);
-        }
-        else
-        {
-          RenderStyle style; 
-          style.applyLut_ = true;
-          style.alpha_ = (layer == 0 ? 1.0f : 0.5f);
-          widget.SetLayerStyle(layer, style);
-        }
-      }
-
-
-      void ConnectSiblingLocations(LayeredSceneWidget& axial,
-                                   LayeredSceneWidget& coronal,
-                                   LayeredSceneWidget& sagittal)
-      {
-        ReferenceLineFactory::Configure(axial, coronal);
-        ReferenceLineFactory::Configure(axial, sagittal);
-        ReferenceLineFactory::Configure(coronal, sagittal);
-      }
-
-
-      void SynchronizeView(const WorldSceneWidget& source,
-                           const ViewportGeometry& view,
-                           LayeredSceneWidget& widget1,
-                           LayeredSceneWidget& widget2,
-                           LayeredSceneWidget& widget3)
-      {
-        if (&source == &widget1 ||
-            &source == &widget2 ||
-            &source == &widget3)
-        {
-          if (&source != &widget1)
-          {
-            widget1.SetView(view);
-          }
-
-          if (&source != &widget2)
-          {
-            widget2.SetView(view);
-          }
-
-          if (&source != &widget3)
-          {
-            widget3.SetView(view);
-          }
-        }
-      }
-
-
-      void SynchronizeSlice(const LayeredSceneWidget& source,
-                            const SliceGeometry& slice,
-                            LayeredSceneWidget& widget1,
-                            LayeredSceneWidget& widget2,
-                            LayeredSceneWidget& widget3)
-      {
-        if (&source == &widget1 ||
-            &source == &widget2 ||
-            &source == &widget3)
-        {
-          if (&source != &widget1)
-          {
-            widget1.SetSlice(slice);
-          }
-
-          if (&source != &widget2)
-          {
-            widget2.SetSlice(slice);
-          }
-
-          if (&source != &widget3)
-          {
-            widget3.SetSlice(slice);
-          }
-        }
-      }
-
-
-      LayeredSceneWidget* CreateWidget()
-      {
-        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
-        widget->Register(dynamic_cast<WorldSceneWidget::IWorldObserver&>(*this));
-        widget->Register(dynamic_cast<LayeredSceneWidget::ISliceObserver&>(*this));
-        return widget.release();
-      }
-
-
-      void CreateLayout(BasicApplicationContext& context)
-      {
-        std::unique_ptr<OrthancStone::LayoutWidget> layout(new OrthancStone::LayoutWidget);
-        layout->SetBackgroundCleared(true);
-        //layout->SetBackgroundColor(255,0,0);
-        layout->SetPadding(5);
-
-        OrthancStone::LayoutWidget& layoutA = dynamic_cast<OrthancStone::LayoutWidget&>
-          (layout->AddWidget(new OrthancStone::LayoutWidget));
-        layoutA.SetPadding(0, 0, 0, 0, 5);
-        layoutA.SetVertical();
-        petAxial_ = &dynamic_cast<LayeredSceneWidget&>(layoutA.AddWidget(CreateWidget()));
-        OrthancStone::LayoutWidget& layoutA2 = dynamic_cast<OrthancStone::LayoutWidget&>
-          (layoutA.AddWidget(new OrthancStone::LayoutWidget));
-        layoutA2.SetPadding(0, 0, 0, 0, 5);
-        petSagittal_ = &dynamic_cast<LayeredSceneWidget&>(layoutA2.AddWidget(CreateWidget()));
-        petCoronal_ = &dynamic_cast<LayeredSceneWidget&>(layoutA2.AddWidget(CreateWidget()));
-
-        OrthancStone::LayoutWidget& layoutB = dynamic_cast<OrthancStone::LayoutWidget&>
-          (layout->AddWidget(new OrthancStone::LayoutWidget));
-        layoutB.SetPadding(0, 0, 0, 0, 5);
-        layoutB.SetVertical();
-        ctAxial_ = &dynamic_cast<LayeredSceneWidget&>(layoutB.AddWidget(CreateWidget()));
-        OrthancStone::LayoutWidget& layoutB2 = dynamic_cast<OrthancStone::LayoutWidget&>
-          (layoutB.AddWidget(new OrthancStone::LayoutWidget));
-        layoutB2.SetPadding(0, 0, 0, 0, 5);
-        ctSagittal_ = &dynamic_cast<LayeredSceneWidget&>(layoutB2.AddWidget(CreateWidget()));
-        ctCoronal_ = &dynamic_cast<LayeredSceneWidget&>(layoutB2.AddWidget(CreateWidget()));
-
-        OrthancStone::LayoutWidget& layoutC = dynamic_cast<OrthancStone::LayoutWidget&>
-          (layout->AddWidget(new OrthancStone::LayoutWidget));
-        layoutC.SetPadding(0, 0, 0, 0, 5);
-        layoutC.SetVertical();
-        fusionAxial_ = &dynamic_cast<LayeredSceneWidget&>(layoutC.AddWidget(CreateWidget()));
-        OrthancStone::LayoutWidget& layoutC2 = dynamic_cast<OrthancStone::LayoutWidget&>
-          (layoutC.AddWidget(new OrthancStone::LayoutWidget));
-        layoutC2.SetPadding(0, 0, 0, 0, 5);
-        fusionSagittal_ = &dynamic_cast<LayeredSceneWidget&>(layoutC2.AddWidget(CreateWidget()));
-        fusionCoronal_ = &dynamic_cast<LayeredSceneWidget&>(layoutC2.AddWidget(CreateWidget()));
-  
-        context.SetCentralWidget(layout.release());
-      }
-
-
-    public:
-      virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("ct", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the CT series")
-          ("pet", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the PET series")
-          ("rt", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the DICOM RT-STRUCT series (optional)")
-          ("threads", boost::program_options::value<unsigned int>()->default_value(3), 
-           "Number of download threads for the CT series")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(BasicApplicationContext& context,
-                              IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        processingEvent_ = true;
-
-        if (parameters.count("ct") != 1 ||
-            parameters.count("pet") != 1)
-        {
-          LOG(ERROR) << "The series ID is missing";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::string ct = parameters["ct"].as<std::string>();
-        std::string pet = parameters["pet"].as<std::string>();
-        unsigned int threads = parameters["threads"].as<unsigned int>();
-
-        VolumeImage& ctVolume = context.AddSeriesVolume(ct, true /* progressive download */, threads);
-        VolumeImage& petVolume = context.AddSeriesVolume(pet, true /* progressive download */, 1);
-
-        // Take the PET volume as the reference for the slices
-        interactorAxial_ = &dynamic_cast<Interactor&>
-          (context.AddInteractor(new Interactor(*this, petVolume, VolumeProjection_Axial, false)));
-        interactorCoronal_ = &dynamic_cast<Interactor&>
-          (context.AddInteractor(new Interactor(*this, petVolume, VolumeProjection_Coronal, false)));
-        interactorSagittal_ = &dynamic_cast<Interactor&>
-          (context.AddInteractor(new Interactor(*this, petVolume, VolumeProjection_Sagittal, true)));
-
-        CreateLayout(context);
-
-        AddLayer(*ctAxial_, ctVolume, true);
-        AddLayer(*ctCoronal_, ctVolume, true);
-        AddLayer(*ctSagittal_, ctVolume, true);
-
-        AddLayer(*petAxial_, petVolume, false);
-        AddLayer(*petCoronal_, petVolume, false);
-        AddLayer(*petSagittal_, petVolume, false);
-
-        AddLayer(*fusionAxial_, ctVolume, true);
-        AddLayer(*fusionAxial_, petVolume, false);
-        AddLayer(*fusionCoronal_, ctVolume, true);
-        AddLayer(*fusionCoronal_, petVolume, false);
-        AddLayer(*fusionSagittal_, ctVolume, true);
-        AddLayer(*fusionSagittal_, petVolume, false);
-
-        if (parameters.count("rt") == 1)
-        {
-          DicomStructureSet& rtStruct = context.AddStructureSet(parameters["rt"].as<std::string>());
-
-          Vector p = rtStruct.GetStructureCenter(0);
-          interactorAxial_->GetCursor().LookupSliceContainingPoint(p);
-
-          ctAxial_->AddLayer(new DicomStructureSetSlicer(rtStruct));
-          petAxial_->AddLayer(new DicomStructureSetSlicer(rtStruct));
-          fusionAxial_->AddLayer(new DicomStructureSetSlicer(rtStruct));
-        }        
-
-        ConnectSiblingLocations(*ctAxial_, *ctCoronal_, *ctSagittal_); 
-        ConnectSiblingLocations(*petAxial_, *petCoronal_, *petSagittal_); 
-        ConnectSiblingLocations(*fusionAxial_, *fusionCoronal_, *fusionSagittal_); 
-
-        interactorAxial_->AddWidget(*ctAxial_);
-        interactorAxial_->AddWidget(*petAxial_);
-        interactorAxial_->AddWidget(*fusionAxial_);
-        
-        interactorCoronal_->AddWidget(*ctCoronal_);
-        interactorCoronal_->AddWidget(*petCoronal_);
-        interactorCoronal_->AddWidget(*fusionCoronal_);
-        
-        interactorSagittal_->AddWidget(*ctSagittal_);
-        interactorSagittal_->AddWidget(*petSagittal_);
-        interactorSagittal_->AddWidget(*fusionSagittal_);
-
-        processingEvent_ = false;
-
-        statusBar.SetMessage("Use the key \"t\" to toggle the fullscreen mode");
-        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
-      }
-
-      virtual void NotifySizeChange(const WorldSceneWidget& source,
-                                    ViewportGeometry& view)
-      {
-        view.FitContent();
-      }
-
-      virtual void NotifyViewChange(const WorldSceneWidget& source,
-                                    const ViewportGeometry& view)
-      {
-        if (!processingEvent_)  // Avoid reentrant calls
-        {
-          processingEvent_ = true;
-
-          SynchronizeView(source, view, *ctAxial_, *petAxial_, *fusionAxial_);
-          SynchronizeView(source, view, *ctCoronal_, *petCoronal_, *fusionCoronal_);
-          SynchronizeView(source, view, *ctSagittal_, *petSagittal_, *fusionSagittal_);
-          
-          processingEvent_ = false;
-        }
-      }
-
-      virtual void NotifySliceContentChange(const LayeredSceneWidget& source,
-                                     const SliceGeometry& slice)
-      {
-        if (!processingEvent_)  // Avoid reentrant calls
-        {
-          processingEvent_ = true;
-
-          SynchronizeSlice(source, slice, *ctAxial_, *petAxial_, *fusionAxial_);
-          SynchronizeSlice(source, slice, *ctCoronal_, *petCoronal_, *fusionCoronal_);
-          SynchronizeSlice(source, slice, *ctSagittal_, *petSagittal_, *fusionSagittal_);
-          
-          processingEvent_ = false;
-        }
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/Qt/SampleMainWindow.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "SampleMainWindow.h"
-
-/**
- * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
- * this makes CMake unable to detect when the UI file changes.
- **/
-#include <ui_SampleMainWindow.h>
-#include "../../../Applications/Samples/SampleApplicationBase.h"
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-
-    SampleMainWindow::SampleMainWindow(
-      OrthancStone::NativeStoneApplicationContext& context,
-      OrthancStone::Samples::SampleSingleCanvasApplicationBase& stoneSampleApplication,
-      QWidget *parent) :
-      QStoneMainWindow(context, parent),
-      ui_(new Ui::SampleMainWindow),
-      stoneSampleApplication_(stoneSampleApplication)
-    {
-      ui_->setupUi(this);
-      SetCentralStoneWidget(*ui_->cairoCentralWidget);
-    }
-
-    SampleMainWindow::~SampleMainWindow()
-    {
-      delete ui_;
-    }
-
-  }
-}
--- a/Applications/Samples/Deprecated/Qt/SampleMainWindow.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-#pragma once
-
-#include "../../../Qt/QCairoWidget.h"
-#include "../../../Qt/QStoneMainWindow.h"
-
-namespace Ui 
-{
-  class SampleMainWindow;
-}
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-
-    class SampleSingleCanvasApplicationBase;
-
-    class SampleMainWindow : public QStoneMainWindow
-    {
-      Q_OBJECT
-
-    private:
-      Ui::SampleMainWindow*   ui_;
-      SampleSingleCanvasApplicationBase&  stoneSampleApplication_;
-
-    public:
-      explicit SampleMainWindow(OrthancStone::NativeStoneApplicationContext& context, SampleSingleCanvasApplicationBase& stoneSampleApplication, QWidget *parent = 0);
-      ~SampleMainWindow();
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/Qt/SampleMainWindow.ui	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SampleMainWindow</class>
- <widget class="QMainWindow" name="SampleMainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>903</width>
-    <height>634</height>
-   </rect>
-  </property>
-  <property name="minimumSize">
-   <size>
-    <width>500</width>
-    <height>300</height>
-   </size>
-  </property>
-  <property name="baseSize">
-   <size>
-    <width>500</width>
-    <height>300</height>
-   </size>
-  </property>
-  <property name="windowTitle">
-   <string>Stone of Orthanc</string>
-  </property>
-  <property name="layoutDirection">
-   <enum>Qt::LeftToRight</enum>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <property name="sizePolicy">
-    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-     <horstretch>0</horstretch>
-     <verstretch>0</verstretch>
-    </sizepolicy>
-   </property>
-   <property name="layoutDirection">
-    <enum>Qt::LeftToRight</enum>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0">
-    <property name="sizeConstraint">
-     <enum>QLayout::SetDefaultConstraint</enum>
-    </property>
-    <item>
-     <widget class="QCairoWidget" name="cairoCentralWidget">
-      <property name="minimumSize">
-       <size>
-        <width>0</width>
-        <height>500</height>
-       </size>
-      </property>
-     </widget>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>903</width>
-     <height>22</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuTest">
-    <property name="title">
-     <string>Test</string>
-    </property>
-   </widget>
-   <addaction name="menuTest"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>QCairoWidget</class>
-   <extends>QGraphicsView</extends>
-   <header location="global">QCairoWidget.h</header>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
--- a/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "SampleMainWindow.h"
-
-/**
- * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
- * this makes CMake unable to detect when the UI file changes.
- **/
-#include <ui_SampleMainWindowWithButtons.h>
-#include "../../../Applications/Samples/SampleApplicationBase.h"
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-
-    SampleMainWindowWithButtons::SampleMainWindowWithButtons(
-      OrthancStone::NativeStoneApplicationContext& context,
-      OrthancStone::Samples::SampleSingleCanvasWithButtonsApplicationBase& stoneSampleApplication,
-      QWidget *parent) :
-      QStoneMainWindow(context, parent),
-      ui_(new Ui::SampleMainWindowWithButtons),
-      stoneSampleApplication_(stoneSampleApplication)
-    {
-      ui_->setupUi(this);
-      SetCentralStoneWidget(*ui_->cairoCentralWidget);
-
-#if QT_VERSION >= 0x050000
-      connect(ui_->toolButton1, &QToolButton::clicked, this, &SampleMainWindowWithButtons::tool1Clicked);
-      connect(ui_->toolButton2, &QToolButton::clicked, this, &SampleMainWindowWithButtons::tool2Clicked);
-      connect(ui_->pushButton1, &QPushButton::clicked, this, &SampleMainWindowWithButtons::pushButton1Clicked);
-      connect(ui_->pushButton1, &QPushButton::clicked, this, &SampleMainWindowWithButtons::pushButton2Clicked);
-#else
-      connect(ui_->toolButton1, SIGNAL(clicked()), this, SLOT(tool1Clicked()));
-      connect(ui_->toolButton2, SIGNAL(clicked()), this, SLOT(tool2Clicked()));
-      connect(ui_->pushButton1, SIGNAL(clicked()), this, SLOT(pushButton1Clicked()));
-      connect(ui_->pushButton1, SIGNAL(clicked()), this, SLOT(pushButton2Clicked()));
-#endif
-
-      std::string pushButton1Name;
-      std::string pushButton2Name;
-      std::string tool1Name;
-      std::string tool2Name;
-      stoneSampleApplication_.GetButtonNames(pushButton1Name, pushButton2Name, tool1Name, tool2Name);
-
-      ui_->toolButton1->setText(QString::fromStdString(tool1Name));
-      ui_->toolButton2->setText(QString::fromStdString(tool2Name));
-      ui_->pushButton1->setText(QString::fromStdString(pushButton1Name));
-      ui_->pushButton2->setText(QString::fromStdString(pushButton2Name));
-    }
-
-    SampleMainWindowWithButtons::~SampleMainWindowWithButtons()
-    {
-      delete ui_;
-    }
-
-    void SampleMainWindowWithButtons::tool1Clicked()
-    {
-      stoneSampleApplication_.OnTool1Clicked();
-    }
-
-    void SampleMainWindowWithButtons::tool2Clicked()
-    {
-      stoneSampleApplication_.OnTool2Clicked();
-    }
-
-    void SampleMainWindowWithButtons::pushButton1Clicked()
-    {
-      stoneSampleApplication_.OnPushButton1Clicked();
-    }
-
-    void SampleMainWindowWithButtons::pushButton2Clicked()
-    {
-      stoneSampleApplication_.OnPushButton2Clicked();
-    }
-
-  }
-}
--- a/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-#pragma once
-
-#include "../../../Qt/QCairoWidget.h"
-#include "../../../Qt/QStoneMainWindow.h"
-
-namespace Ui 
-{
-  class SampleMainWindowWithButtons;
-}
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-
-    class SampleSingleCanvasWithButtonsApplicationBase;
-
-    class SampleMainWindowWithButtons : public QStoneMainWindow
-    {
-      Q_OBJECT
-
-    private:
-      Ui::SampleMainWindowWithButtons*   ui_;
-      SampleSingleCanvasWithButtonsApplicationBase&  stoneSampleApplication_;
-
-    public:
-      explicit SampleMainWindowWithButtons(OrthancStone::NativeStoneApplicationContext& context, SampleSingleCanvasWithButtonsApplicationBase& stoneSampleApplication, QWidget *parent = 0);
-      ~SampleMainWindowWithButtons();
-
-    private slots:
-      void tool1Clicked();
-      void tool2Clicked();
-      void pushButton1Clicked();
-      void pushButton2Clicked();
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.ui	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SampleMainWindowWithButtons</class>
- <widget class="QMainWindow" name="SampleMainWindowWithButtons">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>903</width>
-    <height>634</height>
-   </rect>
-  </property>
-  <property name="minimumSize">
-   <size>
-    <width>500</width>
-    <height>300</height>
-   </size>
-  </property>
-  <property name="baseSize">
-   <size>
-    <width>500</width>
-    <height>300</height>
-   </size>
-  </property>
-  <property name="windowTitle">
-   <string>Stone of Orthanc</string>
-  </property>
-  <property name="layoutDirection">
-   <enum>Qt::LeftToRight</enum>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <property name="sizePolicy">
-    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-     <horstretch>0</horstretch>
-     <verstretch>0</verstretch>
-    </sizepolicy>
-   </property>
-   <property name="layoutDirection">
-    <enum>Qt::LeftToRight</enum>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
-    <property name="sizeConstraint">
-     <enum>QLayout::SetDefaultConstraint</enum>
-    </property>
-    <item>
-     <widget class="QCairoWidget" name="cairoCentralWidget">
-      <property name="minimumSize">
-       <size>
-        <width>0</width>
-        <height>500</height>
-       </size>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <widget class="QGroupBox" name="horizontalGroupBox">
-      <property name="minimumSize">
-       <size>
-        <width>0</width>
-        <height>100</height>
-       </size>
-      </property>
-      <property name="maximumSize">
-       <size>
-        <width>16777215</width>
-        <height>100</height>
-       </size>
-      </property>
-      <layout class="QHBoxLayout" name="horizontalLayout">
-       <item>
-        <widget class="QToolButton" name="toolButton1">
-         <property name="text">
-          <string>tool1</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QToolButton" name="toolButton2">
-         <property name="text">
-          <string>tool2</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButton1">
-         <property name="text">
-          <string>action1</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButton2">
-         <property name="text">
-          <string>action2</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>903</width>
-     <height>22</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuTest">
-    <property name="title">
-     <string>Test</string>
-    </property>
-   </widget>
-   <addaction name="menuTest"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>QCairoWidget</class>
-   <extends>QGraphicsView</extends>
-   <header location="global">QCairoWidget.h</header>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
--- a/Applications/Samples/Deprecated/Qt/SampleQtApplicationRunner.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../../../Qt/QtStoneApplicationRunner.h"
-
-#if ORTHANC_ENABLE_QT != 1
-#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
-#endif
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class SampleQtApplicationRunner : public OrthancStone::QtStoneApplicationRunner
-    {
-    protected:
-      virtual void InitializeMainWindow(OrthancStone::NativeStoneApplicationContext& context)
-      {
-        window_.reset(application_.CreateQtMainWindow());
-      }
-    public:
-      SampleQtApplicationRunner(MessageBroker& broker,
-                                SampleApplicationBase& application)
-        : OrthancStone::QtStoneApplicationRunner(broker, application)
-      {
-      }
-
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/SampleApplicationBase.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../../../Applications/IStoneApplication.h"
-#include "../../../Framework/Deprecated/Widgets/WorldSceneWidget.h"
-
-#if ORTHANC_ENABLE_WASM==1
-#include "../../../Platforms/Wasm/WasmPlatformApplicationAdapter.h"
-#include "../../../Platforms/Wasm/Defaults.h"
-#endif
-
-#if ORTHANC_ENABLE_QT==1
-#include "Qt/SampleMainWindow.h"
-#include "Qt/SampleMainWindowWithButtons.h"
-#endif
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class SampleApplicationBase : public IStoneApplication
-    {
-    private:
-      boost::shared_ptr<Deprecated::IWidget>  mainWidget_;
-
-    public:
-      virtual void Initialize(StoneApplicationContext* context,
-                              Deprecated::IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE
-      {
-      }
-
-      virtual std::string GetTitle() const ORTHANC_OVERRIDE
-      {
-        return "Stone of Orthanc - Sample";
-      }
-
-      /**
-       * In the basic samples, the commands are handled by the platform adapter and NOT
-       * by the application handler
-      */
-      virtual void HandleSerializedMessage(const char* data) ORTHANC_OVERRIDE {};
-
-
-      virtual void Finalize() ORTHANC_OVERRIDE {}
-
-      virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) ORTHANC_OVERRIDE
-      {
-        mainWidget_ = widget;
-      }
-
-      virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() ORTHANC_OVERRIDE
-      {
-        return mainWidget_;
-      }
-
-#if ORTHANC_ENABLE_WASM==1
-      // default implementations for a single canvas named "canvas" in the HTML and an emtpy WasmApplicationAdapter
-
-      virtual void InitializeWasm() ORTHANC_OVERRIDE
-      {
-        AttachWidgetToWasmViewport("canvas", mainWidget_);
-      }
-
-      virtual WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(MessageBroker& broker)
-      {
-        return new WasmPlatformApplicationAdapter(broker, *this);
-      }
-#endif
-
-    };
-
-    // this application actually works in Qt and WASM
-    class SampleSingleCanvasWithButtonsApplicationBase : public SampleApplicationBase
-    {
-public:
-      virtual void OnPushButton1Clicked() {}
-      virtual void OnPushButton2Clicked() {}
-      virtual void OnTool1Clicked() {}
-      virtual void OnTool2Clicked() {}
-
-      virtual void GetButtonNames(std::string& pushButton1,
-                                  std::string& pushButton2,
-                                  std::string& tool1,
-                                  std::string& tool2
-                                  ) {
-        pushButton1 = "action1";
-        pushButton2 = "action2";
-        tool1 = "tool1";
-        tool2 = "tool2";
-      }
-
-#if ORTHANC_ENABLE_QT==1
-      virtual QStoneMainWindow* CreateQtMainWindow() {
-        return new SampleMainWindowWithButtons(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
-      }
-#endif
-
-    };
-
-    // this application actually works in SDL and WASM
-    class SampleSingleCanvasApplicationBase : public SampleApplicationBase
-    {
-public:
-
-#if ORTHANC_ENABLE_QT==1
-      virtual QStoneMainWindow* CreateQtMainWindow() {
-        return new SampleMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
-      }
-#endif
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/SampleInteractor.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-
-#include "../../../Framework/Widgets/LayeredSceneWidget.h"
-#include "../../../Framework/Widgets/IWorldSceneInteractor.h"
-#include "../../../Framework/Toolbox/ParallelSlicesCursor.h"
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    /**
-     * This is a basic mouse interactor for sample applications. It
-     * contains a set of parallel slices in the 3D space. The mouse
-     * wheel events make the widget change the slice that is
-     * displayed.
-     **/
-    class SampleInteractor : public IWorldSceneInteractor
-    {
-    private:
-      ParallelSlicesCursor   cursor_;
-
-    public:
-      SampleInteractor(VolumeImage& volume,
-                       VolumeProjection projection, 
-                       bool reverse)
-      {
-        std::unique_ptr<ParallelSlices> slices(volume.GetGeometry(projection, reverse));
-        cursor_.SetGeometry(*slices);
-      }
-
-      SampleInteractor(ISeriesLoader& series, 
-                       bool reverse)
-      {
-        if (reverse)
-        {
-          std::unique_ptr<ParallelSlices> slices(series.GetGeometry().Reverse());
-          cursor_.SetGeometry(*slices);
-        }
-        else
-        {
-          cursor_.SetGeometry(series.GetGeometry());
-        }
-      }
-
-      SampleInteractor(const ParallelSlices& slices)
-      {
-        cursor_.SetGeometry(slices);
-      }
-
-      ParallelSlicesCursor& GetCursor()
-      {
-        return cursor_;
-      }
-
-      void AddWidget(LayeredSceneWidget& widget)
-      {
-        widget.SetInteractor(*this);
-        widget.SetSlice(cursor_.GetCurrentSlice());
-      }
-
-      virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                          const ViewportGeometry& view,
-                                                          MouseButton button,
-                                                          double x,
-                                                          double y,
-                                                          IStatusBar* statusBar)
-      {
-        return NULL;
-      }
-
-      virtual void MouseOver(CairoContext& context,
-                             WorldSceneWidget& widget,
-                             const ViewportGeometry& view,
-                             double x,
-                             double y,
-                             IStatusBar* statusBar)
-      {
-      }
-
-      virtual void MouseWheel(WorldSceneWidget& widget,
-                              MouseWheelDirection direction,
-                              KeyboardModifiers modifiers,
-                              IStatusBar* statusBar)
-      {
-        if (cursor_.ApplyWheelEvent(direction, modifiers))
-        {
-          dynamic_cast<LayeredSceneWidget&>(widget).SetSlice(cursor_.GetCurrentSlice());
-        }
-      }
-
-      virtual void KeyPressed(WorldSceneWidget& widget,
-                              char key,
-                              KeyboardModifiers modifiers,
-                              IStatusBar* statusBar)
-      {
-      }
-
-      void LookupSliceContainingPoint(LayeredSceneWidget& widget,
-                                      const Vector& p)
-      {
-        if (cursor_.LookupSliceContainingPoint(p))
-        {
-          widget.SetSlice(cursor_.GetCurrentSlice());
-        }
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/SampleList.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-// The macro "ORTHANC_STONE_SAMPLE" must be set by the CMake script
-
-#if ORTHANC_STONE_SAMPLE == 1
-#include "EmptyApplication.h"
-typedef OrthancStone::Samples::EmptyApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 2
-#include "TestPatternApplication.h"
-typedef OrthancStone::Samples::TestPatternApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 3
-#include "SingleFrameApplication.h"
-typedef OrthancStone::Samples::SingleFrameApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 4
-#include "SingleVolumeApplication.h"
-typedef OrthancStone::Samples::SingleVolumeApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 5
-#include "BasicPetCtFusionApplication.h"
-typedef OrthancStone::Samples::BasicPetCtFusionApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 6
-#include "SynchronizedSeriesApplication.h"
-typedef OrthancStone::Samples::SynchronizedSeriesApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 7
-#include "LayoutPetCtFusionApplication.h"
-typedef OrthancStone::Samples::LayoutPetCtFusionApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 8
-#include "SimpleViewerApplicationSingleFile.h"
-typedef OrthancStone::Samples::SimpleViewerApplication SampleApplication;
-
-#elif ORTHANC_STONE_SAMPLE == 9
-#include "SingleFrameEditorApplication.h"
-typedef OrthancStone::Samples::SingleFrameEditorApplication SampleApplication;
-
-#else
-#error Please set the ORTHANC_STONE_SAMPLE macro
-#endif
--- a/Applications/Samples/Deprecated/SampleMainNative.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SampleList.h"
-#if ORTHANC_ENABLE_SDL==1
-#include "../../Sdl/SdlStoneApplicationRunner.h"
-#endif
-#if ORTHANC_ENABLE_QT==1
-#include "Qt/SampleQtApplicationRunner.h"
-#endif
-
-int main(int argc, char* argv[]) 
-{
-  boost::shared_ptr<SampleApplication> sampleStoneApplication(new SampleApplication);
-
-#if ORTHANC_ENABLE_SDL==1
-  OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(sampleStoneApplication);
-  return sdlApplicationRunner.Execute(argc, argv);
-#endif
-  
-#if ORTHANC_ENABLE_QT==1
-  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(sampleStoneApplication);
-  return qtAppRunner.Execute(argc, argv);
-#endif
-}
-
--- a/Applications/Samples/Deprecated/SampleMainWasm.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "Platforms/Wasm/WasmWebService.h"
-#include "Platforms/Wasm/WasmViewport.h"
-
-#include <emscripten/emscripten.h>
-
-#include "SampleList.h"
-
-
-OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) 
-{
-  return new SampleApplication(broker);
-}
-
-OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, OrthancStone::IStoneApplication* application)
-{
-  return dynamic_cast<SampleApplication*>(application)->CreateWasmApplicationAdapter(broker);
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Samples-status.md	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-Executable versions
-================
-Generic options
-----------------------
-```
-("help", "Display this help and exit")
-("verbose", "Be verbose in logs")
-("orthanc", boost::program_options::value<std::string>()
-  ->default_value("http://localhost:8042/"),
-  "URL to the Orthanc server")
-("username", "Username for the Orthanc server")
-("password", "Password for the Orthanc server")
-("https-verify", boost::program_options::value<bool>()
-  ->default_value(true), "Check HTTPS certificates")
-```
-OrthancStoneSimpleViewer
--------------------------------------
-- Options:
-    ```
-    - "studyId", std::string, "Orthanc ID of the study"
-    ```
-- study loading works OK
-- Invert does not work:
-```
-void SimpleViewerApplication::ExecuteAction(SimpleViewerApplication::Actions action)
-  {
-    // TODO
-  }
-```
-
-OrthancStoneSimpleViewerSingleFile
--------------------------------------
-- Options:
-    ```
-    - "studyId", std::string, "Orthanc ID of the study"
-    ```
-
-Study loading works.
-
-The `line` and `circle` buttons work and call this:
-```
-virtual void OnTool1Clicked()
-{
-  currentTool_ = Tools_LineMeasure;
-}
-
-virtual void OnTool2Clicked()
-{
-  currentTool_ = Tools_CircleMeasure;
-}
-```
-The `action1` and `action2` buttons are not connected
-
-The following is displayed in the console at launch time:
-```
-W0313 12:20:12.790449 NativeStoneApplicationRunner.cpp:55] Use the key "s" to reinitialize the layout
-W0313 12:20:12.790449 NativeStoneApplicationRunner.cpp:55] Use the key "n" to go to next image in the main viewport
-```
-However, when looking at `MainWidgetInteractor::KeyPressed` (`SimpleViewerApplicationSingleFile.h:169`), only the following is processed:
-- 's': reset layout
-- 'l': select line tool
-- 'c': select circle tool
-
-OrthancStoneSingleFrame
--------------------------------------
-```
-generic.add_options()
-("instance", boost::program_options::value<std::string>(), 
-"Orthanc ID of the instance")
-("frame", boost::program_options::value<unsigned int>()
-  ->default_value(0),
-"Number of the frame, for multi-frame DICOM instances")
-("smooth", boost::program_options::value<bool>()
-  ->default_value(true), 
-"Enable bilinear interpolation to smooth the image");
-```
-only key handled in `KeyPressed` is `s` to call `widget.FitContent()`
-
-
-OrthancStoneSingleFrameEditor
--------------------------------------
-```
-generic.add_options()
-("instance", boost::program_options::value<std::string>(),
-"Orthanc ID of the instance")
-("frame", boost::program_options::value<unsigned int>()
-  ->default_value(0),
-"Number of the frame, for multi-frame DICOM instances");
-```
-Available commands in `KeyPressed` (`SingleFrameEditorApplication.h:280`): 
-- 'a' widget.FitContent()
-- 'c' Crop tool
-- 'm' Mask tool
-- 'd' dump to json and diplay result (?)
-- 'e' export current view to Dicom with dummy tags (?)
-- 'i' wdiget.SwitchInvert
-- 't' Move tool
-- 'n' switch between nearest and bilinear interpolation
-- 'r' Rotate tool
-- 's' Resize tool
-- 'w' Windowing tool
-- 'ctrl+y' redo
-- 'ctrl+z' undo
--- a/Applications/Samples/Deprecated/SimpleViewer/AppStatus.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#pragma once
-
-#include <string>
-
-
-namespace SimpleViewer
-{
-  struct AppStatus
-  {
-    std::string patientId;
-    std::string studyDescription;
-    std::string currentInstanceIdInMainViewport;
-    // note: if you add members here, update the serialization code below and deserialization in simple-viewer.ts -> onAppStatusUpdated()
-
-
-    AppStatus()
-    {
-    }
-
-    void ToJson(Json::Value &output) const
-    {
-      output["patientId"] = patientId;
-      output["studyDescription"] = studyDescription;
-      output["currentInstanceIdInMainViewport"] = currentInstanceIdInMainViewport;
-    }
-  };
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "MainWidgetInteractor.h"
-
-#include "SimpleViewerApplication.h"
-
-namespace SimpleViewer {
-
-  Deprecated::IWorldSceneMouseTracker* MainWidgetInteractor::CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                                    const Deprecated::ViewportGeometry& view,
-                                                                    MouseButton button,
-                                                                    KeyboardModifiers modifiers,
-                                                                    int viewportX,
-                                                                    int viewportY,
-                                                                    double x,
-                                                                    double y,
-                                                                    Deprecated::IStatusBar* statusBar,
-                                                                    const std::vector<Deprecated::Touch>& displayTouches)
-  {
-    if (button == MouseButton_Left)
-    {
-      if (application_.GetCurrentTool() == Tool_LineMeasure)
-      {
-        return new Deprecated::LineMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
-                                      x, y, 255, 0, 0, application_.GetFont());
-      }
-      else if (application_.GetCurrentTool() == Tool_CircleMeasure)
-      {
-        return new Deprecated::CircleMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
-                                        x, y, 255, 0, 0, application_.GetFont());
-      }
-      else if (application_.GetCurrentTool() == Tool_Crop)
-      {
-        // TODO
-      }
-      else if (application_.GetCurrentTool() == Tool_Windowing)
-      {
-        // TODO
-      }
-      else if (application_.GetCurrentTool() == Tool_Zoom)
-      {
-        // TODO
-      }
-      else if (application_.GetCurrentTool() == Tool_Pan)
-      {
-        // TODO
-      }
-    }
-    return NULL;
-  }
-
-  void MainWidgetInteractor::MouseOver(CairoContext& context,
-                                       Deprecated::WorldSceneWidget& widget,
-                                       const Deprecated::ViewportGeometry& view,
-                                       double x,
-                                       double y,
-                                       Deprecated::IStatusBar* statusBar)
-  {
-    if (statusBar != NULL)
-    {
-      Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
-
-      char buf[64];
-      sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
-              p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
-      statusBar->SetMessage(buf);
-    }
-  }
-
-  void MainWidgetInteractor::MouseWheel(Deprecated::WorldSceneWidget& widget,
-                                        MouseWheelDirection direction,
-                                        KeyboardModifiers modifiers,
-                                        Deprecated::IStatusBar* statusBar)
-  {
-  }
-
-  void MainWidgetInteractor::KeyPressed(Deprecated::WorldSceneWidget& widget,
-                                        KeyboardKeys key,
-                                        char keyChar,
-                                        KeyboardModifiers modifiers,
-                                        Deprecated::IStatusBar* statusBar)
-  {
-    switch (keyChar)
-    {
-    case 's':
-      widget.FitContent();
-      break;
-
-    default:
-      break;
-    }
-  }
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#pragma once
-
-#include "../../../../Framework/Deprecated/Widgets/IWorldSceneInteractor.h"
-
-using namespace OrthancStone;
-
-namespace SimpleViewer {
-
-  class SimpleViewerApplication;
-
-  class MainWidgetInteractor : public Deprecated::IWorldSceneInteractor
-  {
-  private:
-    SimpleViewerApplication&  application_;
-
-  public:
-    MainWidgetInteractor(SimpleViewerApplication&  application) :
-      application_(application)
-    {
-    }
-
-    /**
-        WorldSceneWidget: 
-    */
-    virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                                    const Deprecated::ViewportGeometry& view,
-                                                                    MouseButton button,
-                                                                    KeyboardModifiers modifiers,
-                                                                    int viewportX,
-                                                                    int viewportY,
-                                                                    double x,
-                                                                    double y,
-                                                                    Deprecated::IStatusBar* statusBar,
-                                                                    const std::vector<Deprecated::Touch>& displayTouches);
-
-    virtual void MouseOver(CairoContext& context,
-                           Deprecated::WorldSceneWidget& widget,
-                           const Deprecated::ViewportGeometry& view,
-                           double x,
-                           double y,
-                           Deprecated::IStatusBar* statusBar);
-
-    virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
-                            MouseWheelDirection direction,
-                            KeyboardModifiers modifiers,
-                            Deprecated::IStatusBar* statusBar);
-
-    virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
-                            KeyboardKeys key,
-                            char keyChar,
-                            KeyboardModifiers modifiers,
-                            Deprecated::IStatusBar* statusBar);
-  };
-
-
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "SimpleViewerMainWindow.h"
-
-/**
- * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
- * this makes CMake unable to detect when the UI file changes.
- **/
-#include <ui_SimpleViewerMainWindow.h>
-#include "../../SimpleViewerApplication.h"
-
-
-namespace SimpleViewer
-{
-  template<typename T, typename U>
-  bool ExecuteCommand(U* handler, const T& command)
-  {
-    std::string serializedCommand = StoneSerialize(command);
-    StoneDispatchToHandler(serializedCommand, handler);
-  }
-
-  SimpleViewerMainWindow::SimpleViewerMainWindow(
-    OrthancStone::NativeStoneApplicationContext& context,
-    SimpleViewerApplication& stoneApplication,
-    QWidget *parent) :
-    QStoneMainWindow(context, parent),
-    ui_(new Ui::SimpleViewerMainWindow),
-    stoneApplication_(stoneApplication)
-  {
-    ui_->setupUi(this);
-    SetCentralStoneWidget(*ui_->cairoCentralWidget);
-
-#if QT_VERSION >= 0x050000
-    connect(ui_->toolButtonCrop, &QToolButton::clicked, this, &SimpleViewerMainWindow::cropClicked);
-    connect(ui_->pushButtonUndoCrop, &QToolButton::clicked, this, &SimpleViewerMainWindow::undoCropClicked);
-    connect(ui_->toolButtonLine, &QToolButton::clicked, this, &SimpleViewerMainWindow::lineClicked);
-    connect(ui_->toolButtonCircle, &QToolButton::clicked, this, &SimpleViewerMainWindow::circleClicked);
-    connect(ui_->toolButtonWindowing, &QToolButton::clicked, this, &SimpleViewerMainWindow::windowingClicked);
-    connect(ui_->pushButtonRotate, &QPushButton::clicked, this, &SimpleViewerMainWindow::rotateClicked);
-    connect(ui_->pushButtonInvert, &QPushButton::clicked, this, &SimpleViewerMainWindow::invertClicked);
-#else
-    connect(ui_->toolButtonCrop, SIGNAL(clicked()), this, SLOT(cropClicked()));
-    connect(ui_->toolButtonLine, SIGNAL(clicked()), this, SLOT(lineClicked()));
-    connect(ui_->toolButtonCircle, SIGNAL(clicked()), this, SLOT(circleClicked()));
-    connect(ui_->toolButtonWindowing, SIGNAL(clicked()), this, SLOT(windowingClicked()));
-    connect(ui_->pushButtonUndoCrop, SIGNAL(clicked()), this, SLOT(undoCropClicked()));
-    connect(ui_->pushButtonRotate, SIGNAL(clicked()), this, SLOT(rotateClicked()));
-    connect(ui_->pushButtonInvert, SIGNAL(clicked()), this, SLOT(invertClicked()));
-#endif
-  }
-
-  SimpleViewerMainWindow::~SimpleViewerMainWindow()
-  {
-    delete ui_;
-  }
-
-  void SimpleViewerMainWindow::cropClicked()
-  {
-    stoneApplication_.ExecuteCommand(SelectTool(Tool_Crop));
-  }
-
-  void SimpleViewerMainWindow::undoCropClicked()
-  {
-    stoneApplication_.ExecuteCommand(Action(ActionType_UndoCrop));
-  }
-
-  void SimpleViewerMainWindow::lineClicked()
-  {
-    stoneApplication_.ExecuteCommand(SelectTool(Tool_LineMeasure));
-  }
-
-  void SimpleViewerMainWindow::circleClicked()
-  {
-    stoneApplication_.ExecuteCommand(SelectTool(Tool_CircleMeasure));
-  }
-
-  void SimpleViewerMainWindow::windowingClicked()
-  {
-    stoneApplication_.ExecuteCommand(SelectTool(Tool_Windowing));
-  }
-
-  void SimpleViewerMainWindow::rotateClicked()
-  {
-    stoneApplication_.ExecuteCommand(Action(ActionType_Rotate));
-  }
-
-  void SimpleViewerMainWindow::invertClicked()
-  {
-    stoneApplication_.ExecuteCommand(Action(ActionType_Invert));
-  }
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-#pragma once
-
-#include <Applications/Qt/QCairoWidget.h>
-#include <Applications/Qt/QStoneMainWindow.h>
-
-namespace Ui 
-{
-  class SimpleViewerMainWindow;
-}
-
-using namespace OrthancStone;
-
-namespace SimpleViewer
-{
-  class SimpleViewerApplication;
-
-  class SimpleViewerMainWindow : public QStoneMainWindow
-  {
-    Q_OBJECT
-
-  private:
-    Ui::SimpleViewerMainWindow*   ui_;
-    SimpleViewerApplication&      stoneApplication_;
-
-  public:
-    explicit SimpleViewerMainWindow(OrthancStone::NativeStoneApplicationContext& context, SimpleViewerApplication& stoneApplication, QWidget *parent = 0);
-    ~SimpleViewerMainWindow();
-
-  private slots:
-    void cropClicked();
-    void undoCropClicked();
-    void rotateClicked();
-    void windowingClicked();
-    void lineClicked();
-    void circleClicked();
-    void invertClicked();
-  };
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SimpleViewerMainWindow</class>
- <widget class="QMainWindow" name="SimpleViewerMainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>903</width>
-    <height>634</height>
-   </rect>
-  </property>
-  <property name="minimumSize">
-   <size>
-    <width>500</width>
-    <height>300</height>
-   </size>
-  </property>
-  <property name="baseSize">
-   <size>
-    <width>500</width>
-    <height>300</height>
-   </size>
-  </property>
-  <property name="windowTitle">
-   <string>Stone of Orthanc</string>
-  </property>
-  <property name="layoutDirection">
-   <enum>Qt::LeftToRight</enum>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <property name="sizePolicy">
-    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-     <horstretch>0</horstretch>
-     <verstretch>0</verstretch>
-    </sizepolicy>
-   </property>
-   <property name="layoutDirection">
-    <enum>Qt::LeftToRight</enum>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
-    <property name="sizeConstraint">
-     <enum>QLayout::SetDefaultConstraint</enum>
-    </property>
-    <item>
-     <widget class="QCairoWidget" name="cairoCentralWidget">
-      <property name="minimumSize">
-       <size>
-        <width>0</width>
-        <height>500</height>
-       </size>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <widget class="QGroupBox" name="horizontalGroupBox">
-      <property name="minimumSize">
-       <size>
-        <width>0</width>
-        <height>100</height>
-       </size>
-      </property>
-      <property name="maximumSize">
-       <size>
-        <width>16777215</width>
-        <height>100</height>
-       </size>
-      </property>
-      <layout class="QHBoxLayout" name="horizontalLayout">
-       <item>
-        <widget class="QToolButton" name="toolButtonWindowing">
-         <property name="text">
-          <string>windowing</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QToolButton" name="toolButtonCrop">
-         <property name="text">
-          <string>crop</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButtonUndoCrop">
-         <property name="text">
-          <string>undo crop</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QToolButton" name="toolButtonLine">
-         <property name="text">
-          <string>line</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QToolButton" name="toolButtonCircle">
-         <property name="text">
-          <string>circle</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButtonRotate">
-         <property name="text">
-          <string>rotate</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButtonInvert">
-         <property name="text">
-          <string>invert</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>903</width>
-     <height>22</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuTest">
-    <property name="title">
-     <string>Test</string>
-    </property>
-   </widget>
-   <addaction name="menuTest"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>QCairoWidget</class>
-   <extends>QGraphicsView</extends>
-   <header location="global">QCairoWidget.h</header>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
--- a/Applications/Samples/Deprecated/SimpleViewer/Qt/mainQt.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-#include "Applications/Qt/QtStoneApplicationRunner.h"
-
-#include "../../SimpleViewerApplication.h"
-#include "Framework/Messages/MessageBroker.h"
-
-
-int main(int argc, char* argv[]) 
-{
-  OrthancStone::MessageBroker broker;
-  SimpleViewer::SimpleViewerApplication stoneApplication(broker);
-
-  OrthancStone::QtStoneApplicationRunner qtAppRunner(broker, stoneApplication);
-  return qtAppRunner.Execute(argc, argv);
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SimpleViewerApplication.h"
-
-#if ORTHANC_ENABLE_QT == 1
-#  include "Qt/SimpleViewerMainWindow.h"
-#endif
-
-#if ORTHANC_ENABLE_WASM == 1
-#  include <Platforms/Wasm/WasmViewport.h>
-#endif
-
-namespace SimpleViewer
-{
-
-  void SimpleViewerApplication::Initialize(StoneApplicationContext* context,
-                                           Deprecated::IStatusBar& statusBar,
-                                           const boost::program_options::variables_map& parameters)
-  {
-    context_ = context;
-    statusBar_ = &statusBar;
-
-    {// initialize viewports and layout
-      mainLayout_ = new Deprecated::LayoutWidget("main-layout");
-      mainLayout_->SetPadding(10);
-      mainLayout_->SetBackgroundCleared(true);
-      mainLayout_->SetBackgroundColor(0, 0, 0);
-      mainLayout_->SetHorizontal();
-
-      thumbnailsLayout_ = new Deprecated::LayoutWidget("thumbnail-layout");
-      thumbnailsLayout_->SetPadding(10);
-      thumbnailsLayout_->SetBackgroundCleared(true);
-      thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
-      thumbnailsLayout_->SetVertical();
-
-      mainWidget_ = new Deprecated::SliceViewerWidget(IObserver::GetBroker(), "main-viewport");
-      //mainWidget_->RegisterObserver(*this);
-
-      // hierarchy
-      mainLayout_->AddWidget(thumbnailsLayout_);
-      mainLayout_->AddWidget(mainWidget_);
-
-      // sources
-      smartLoader_.reset(new Deprecated::SmartLoader(IObserver::GetBroker(), context->GetOrthancApiClient()));
-      smartLoader_->SetImageQuality(Deprecated::SliceImageQuality_FullPam);
-
-      mainLayout_->SetTransmitMouseOver(true);
-      mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
-      mainWidget_->SetInteractor(*mainWidgetInteractor_);
-      thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
-    }
-
-    statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
-    statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport");
-
-
-    if (parameters.count("studyId") < 1)
-    {
-      LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
-      context->GetOrthancApiClient().GetJsonAsync("/studies", new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyListReceived));
-    }
-    else
-    {
-      SelectStudy(parameters["studyId"].as<std::string>());
-    }
-  }
-
-
-  void SimpleViewerApplication::DeclareStartupOptions(boost::program_options::options_description& options)
-  {
-    boost::program_options::options_description generic("Sample options");
-    generic.add_options()
-        ("studyId", boost::program_options::value<std::string>(),
-         "Orthanc ID of the study")
-        ;
-
-    options.add(generic);
-  }
-
-  void SimpleViewerApplication::OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& response = message.GetJson();
-
-    if (response.isArray() &&
-        response.size() >= 1)
-    {
-      SelectStudy(response[0].asString());
-    }
-  }
-  void SimpleViewerApplication::OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& response = message.GetJson();
-
-    if (response.isObject() && response["Series"].isArray())
-    {
-      for (size_t i=0; i < response["Series"].size(); i++)
-      {
-        context_->GetOrthancApiClient().GetJsonAsync("/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnSeriesReceived));
-      }
-    }
-  }
-
-  void SimpleViewerApplication::OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& response = message.GetJson();
-
-    if (response.isObject() &&
-        response["Instances"].isArray() &&
-        response["Instances"].size() > 0)
-    {
-      // keep track of all instances IDs
-      const std::string& seriesId = response["ID"].asString();
-      seriesTags_[seriesId] = response;
-      instancesIdsPerSeriesId_[seriesId] = std::vector<std::string>();
-      for (size_t i = 0; i < response["Instances"].size(); i++)
-      {
-        const std::string& instanceId = response["Instances"][static_cast<int>(i)].asString();
-        instancesIdsPerSeriesId_[seriesId].push_back(instanceId);
-      }
-
-      // load the first instance in the thumbnail
-      LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
-
-      // if this is the first thumbnail loaded, load the first instance in the mainWidget
-      if (mainWidget_->GetLayerCount() == 0)
-      {
-        smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
-      }
-    }
-  }
-
-  void SimpleViewerApplication::LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
-  {
-    LOG(INFO) << "Loading thumbnail for series " << seriesId;
-    
-    Deprecated::SliceViewerWidget* thumbnailWidget = 
-      new Deprecated::SliceViewerWidget(IObserver::GetBroker(), "thumbnail-series-" + seriesId);
-    thumbnails_.push_back(thumbnailWidget);
-    thumbnailsLayout_->AddWidget(thumbnailWidget);
-    
-    thumbnailWidget->RegisterObserverCallback(
-      new Callable<SimpleViewerApplication, Deprecated::SliceViewerWidget::GeometryChangedMessage>
-      (*this, &SimpleViewerApplication::OnWidgetGeometryChanged));
-    
-    smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
-    thumbnailWidget->SetInteractor(*thumbnailInteractor_);
-  }
-
-  void SimpleViewerApplication::SelectStudy(const std::string& studyId)
-  {
-    context_->GetOrthancApiClient().GetJsonAsync("/studies/" + studyId, new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyReceived));
-  }
-
-  void SimpleViewerApplication::OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
-  {
-    // TODO: The "const_cast" could probably be replaced by "mainWidget_"
-    const_cast<Deprecated::SliceViewerWidget&>(message.GetOrigin()).FitContent();
-  }
-
-  void SimpleViewerApplication::SelectSeriesInMainViewport(const std::string& seriesId)
-  {
-    smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
-  }
-
-  bool SimpleViewerApplication::Handle(const StoneSampleCommands::SelectTool& value)
-  {
-    currentTool_ = value.tool;
-    return true;
-  }
-
-  bool SimpleViewerApplication::Handle(const StoneSampleCommands::Action& value)
-  {
-    switch (value.type)
-    {
-    case ActionType_Invert:
-      // TODO
-      break;
-    case ActionType_UndoCrop:
-      // TODO
-      break;
-    case ActionType_Rotate:
-      // TODO
-      break;
-    default:
-      throw std::runtime_error("Action type not supported");
-    }
-    return true;
-  }
-
-#if ORTHANC_ENABLE_QT==1
-  QStoneMainWindow* SimpleViewerApplication::CreateQtMainWindow()
-  {
-    return new SimpleViewerMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
-  }
-#endif
-
-#if ORTHANC_ENABLE_WASM==1
-  void SimpleViewerApplication::InitializeWasm() {
-
-    AttachWidgetToWasmViewport("canvasThumbnails", thumbnailsLayout_);
-    AttachWidgetToWasmViewport("canvasMain", mainWidget_);
-  }
-#endif
-
-
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
- /*
- This header contains the command definitions for the sample applications
- */
-#include "Applications/Samples/StoneSampleCommands_generated.hpp"
-using namespace StoneSampleCommands;
-
-#include "Applications/IStoneApplication.h"
-
-#include "../../../../Framework/Deprecated/Layers/CircleMeasureTracker.h"
-#include "../../../../Framework/Deprecated/Layers/LineMeasureTracker.h"
-#include "../../../../Framework/Deprecated/SmartLoader.h"
-#include "../../../../Framework/Deprecated/Widgets/LayoutWidget.h"
-#include "../../../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
-#include "../../../../Framework/Messages/IObserver.h"
-
-#if ORTHANC_ENABLE_WASM==1
-#include "Platforms/Wasm/WasmPlatformApplicationAdapter.h"
-#include "Platforms/Wasm/Defaults.h"
-#endif
-
-#if ORTHANC_ENABLE_QT==1
-#include "Qt/SimpleViewerMainWindow.h"
-#endif
-
-#include <Core/Images/Font.h>
-#include <Core/Logging.h>
-
-#include "ThumbnailInteractor.h"
-#include "MainWidgetInteractor.h"
-#include "AppStatus.h"
-
-using namespace OrthancStone;
-
-
-namespace SimpleViewer
-{
-
-  class SimpleViewerApplication
-    : public IStoneApplication
-    , public IObserver
-    , public IObservable
-    , public StoneSampleCommands::IHandler
-  {
-  public:
-
-    struct StatusUpdatedMessage : public IMessage
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-
-      const AppStatus& status_;
-
-      StatusUpdatedMessage(const AppStatus& status)
-        : status_(status)
-      {
-      }
-    };
-
-  private:
-    Tool                                currentTool_;
-
-    std::unique_ptr<MainWidgetInteractor> mainWidgetInteractor_;
-    std::unique_ptr<ThumbnailInteractor>  thumbnailInteractor_;
-    Deprecated::LayoutWidget*                       mainLayout_;
-    Deprecated::LayoutWidget*                       thumbnailsLayout_;
-    Deprecated::SliceViewerWidget*                  mainWidget_;
-    std::vector<Deprecated::SliceViewerWidget*>     thumbnails_;
-    std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
-    std::map<std::string, Json::Value>  seriesTags_;
-    unsigned int                        currentInstanceIndex_;
-    Deprecated::WidgetViewport*       wasmViewport1_;
-    Deprecated::WidgetViewport*       wasmViewport2_;
-
-    Deprecated::IStatusBar*                         statusBar_;
-    std::unique_ptr<Deprecated::SmartLoader>          smartLoader_;
-
-    Orthanc::Font                       font_;
-
-  public:
-    SimpleViewerApplication(MessageBroker& broker) :
-      IObserver(broker),
-      IObservable(broker),
-      currentTool_(StoneSampleCommands::Tool_LineMeasure),
-      mainLayout_(NULL),
-      currentInstanceIndex_(0),
-      wasmViewport1_(NULL),
-      wasmViewport2_(NULL)
-    {
-      font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
-    }
-
-    virtual void Finalize() ORTHANC_OVERRIDE {}
-    virtual Deprecated::IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainLayout_;}
-
-    virtual void DeclareStartupOptions(boost::program_options::options_description& options) ORTHANC_OVERRIDE;
-    virtual void Initialize(StoneApplicationContext* context,
-                            Deprecated::IStatusBar& statusBar,
-                            const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE;
-
-    void OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId);
-
-    void SelectStudy(const std::string& studyId);
-
-    void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message);
-
-    void SelectSeriesInMainViewport(const std::string& seriesId);
-
-
-    Tool GetCurrentTool() const
-    {
-      return currentTool_;
-    }
-
-    const Orthanc::Font& GetFont() const
-    {
-      return font_;
-    }
-
-    // ExecuteAction method was empty (its body was a single "TODO" comment)
-    virtual bool Handle(const SelectTool& value) ORTHANC_OVERRIDE;
-    virtual bool Handle(const Action& value) ORTHANC_OVERRIDE;
-
-    template<typename T>
-    bool ExecuteCommand(const T& cmd)
-    {
-      std::string cmdStr = StoneSampleCommands::StoneSerialize(cmd);
-      return StoneSampleCommands::StoneDispatchToHandler(cmdStr, this);
-    }
-
-    virtual void HandleSerializedMessage(const char* data) ORTHANC_OVERRIDE
-    {
-      StoneSampleCommands::StoneDispatchToHandler(data, this);
-    }
-
-    virtual std::string GetTitle() const ORTHANC_OVERRIDE {return "SimpleViewer";}
-
-#if ORTHANC_ENABLE_WASM==1
-    virtual void InitializeWasm() ORTHANC_OVERRIDE;
-#endif
-
-#if ORTHANC_ENABLE_QT==1
-    virtual QStoneMainWindow* CreateQtMainWindow();
-#endif
-  };
-
-
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "ThumbnailInteractor.h"
-
-#include "SimpleViewerApplication.h"
-
-namespace SimpleViewer {
-
-  Deprecated::IWorldSceneMouseTracker* ThumbnailInteractor::CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                                   const Deprecated::ViewportGeometry& view,
-                                                                   MouseButton button,
-                                                                   KeyboardModifiers modifiers,
-                                                                   int viewportX,
-                                                                   int viewportY,
-                                                                   double x,
-                                                                   double y,
-                                                                   Deprecated::IStatusBar* statusBar,
-                                                                   const std::vector<Deprecated::Touch>& displayTouches)
-  {
-    if (button == MouseButton_Left)
-    {
-      statusBar->SetMessage("selected thumbnail " + widget.GetName());
-      std::string seriesId = widget.GetName().substr(strlen("thumbnail-series-"));
-      application_.SelectSeriesInMainViewport(seriesId);
-    }
-    return NULL;
-  }
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../../../../Framework/Deprecated/Widgets/IWorldSceneInteractor.h"
-
-using namespace OrthancStone;
-
-namespace SimpleViewer {
-
-  class SimpleViewerApplication;
-
-  class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
-  {
-  private:
-    SimpleViewerApplication&  application_;
-  public:
-    ThumbnailInteractor(SimpleViewerApplication&  application) :
-      application_(application)
-    {
-    }
-
-    virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                                    const Deprecated::ViewportGeometry& view,
-                                                                    MouseButton button,
-                                                                    KeyboardModifiers modifiers,
-                                                                    int viewportX,
-                                                                    int viewportY,
-                                                                    double x,
-                                                                    double y,
-                                                                    Deprecated::IStatusBar* statusBar,
-                                                                    const std::vector<Deprecated::Touch>& displayTouches);
-
-    virtual void MouseOver(CairoContext& context,
-                           Deprecated::WorldSceneWidget& widget,
-                           const Deprecated::ViewportGeometry& view,
-                           double x,
-                           double y,
-                           Deprecated::IStatusBar* statusBar)
-    {}
-
-    virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
-                            MouseWheelDirection direction,
-                            KeyboardModifiers modifiers,
-                            Deprecated::IStatusBar* statusBar)
-    {}
-
-    virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
-                            KeyboardKeys key,
-                            char keyChar,
-                            KeyboardModifiers modifiers,
-                            Deprecated::IStatusBar* statusBar)
-    {}
-
-  };
-
-
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "SimpleViewerWasmApplicationAdapter.h"
-
-namespace SimpleViewer
-{
-
-  SimpleViewerWasmApplicationAdapter::SimpleViewerWasmApplicationAdapter(MessageBroker &broker, SimpleViewerApplication &application)
-      : WasmPlatformApplicationAdapter(broker, application),
-        viewerApplication_(application)
-  {
-    application.RegisterObserverCallback(new Callable<SimpleViewerWasmApplicationAdapter, SimpleViewerApplication::StatusUpdatedMessage>(*this, &SimpleViewerWasmApplicationAdapter::OnStatusUpdated));
-  }
-
-  void SimpleViewerWasmApplicationAdapter::OnStatusUpdated(const SimpleViewerApplication::StatusUpdatedMessage &message)
-  {
-    Json::Value statusJson;
-    message.status_.ToJson(statusJson);
-
-    Json::Value event;
-    event["event"] = "appStatusUpdated";
-    event["data"] = statusJson;
-
-    Json::StreamWriterBuilder builder;
-    std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
-    std::ostringstream outputStr;
-
-    writer->write(event, &outputStr);
-
-    NotifyStatusUpdateFromCppToWebWithString(outputStr.str());
-  }
-
-} // namespace SimpleViewer
\ No newline at end of file
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#pragma once
-
-#include <string>
-#include <Framework/Messages/IObserver.h>
-#include <Platforms/Wasm/WasmPlatformApplicationAdapter.h>
-
-#include "../../SimpleViewerApplication.h"
-
-namespace SimpleViewer {
-
-  class SimpleViewerWasmApplicationAdapter : public WasmPlatformApplicationAdapter
-    {
-      SimpleViewerApplication&  viewerApplication_;
-
-    public:
-      SimpleViewerWasmApplicationAdapter(MessageBroker& broker, SimpleViewerApplication& application);
-
-    private:
-      void OnStatusUpdated(const SimpleViewerApplication::StatusUpdatedMessage& message);
-
-    };
-
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/mainWasm.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "Platforms/Wasm/WasmWebService.h"
-#include "Platforms/Wasm/WasmViewport.h"
-
-#include <emscripten/emscripten.h>
-
-#include "../../SimpleViewerApplication.h"
-#include "SimpleViewerWasmApplicationAdapter.h"
-
-
-OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) {
-  
-  return new SimpleViewer::SimpleViewerApplication(broker);
-}
-
-OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, IStoneApplication* application)
-{
-  return new SimpleViewer::SimpleViewerWasmApplicationAdapter(broker, *(dynamic_cast<SimpleViewer::SimpleViewerApplication*>(application)));
-}
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <!-- Disable pinch zoom on mobile devices -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta name="HandheldFriendly" content="true" />
-
-    <title>Simple Viewer</title>
-    <link href="styles.css" rel="stylesheet" />
-
-<body>
-  <div id="breadcrumb">
-    <span id="label-patient-id"></span>
-    <span id="label-study-description"></span>
-    <span id="label-series-description"></span>
-  </div>
-  <div style="height: calc(100% - 50px)">
-    <div style="width: 20%; height: 100%; display: inline-block">
-      <canvas id="canvasThumbnails"></canvas>
-    </div>
-    <div style="width: 70%; height: 100%; display: inline-block">
-      <canvas id="canvasMain"></canvas>
-    </div>
-  </div>
-  <div id="toolbox" style="height: 50px">
-    <button tool-selector="line-measure" class="tool-selector">line</button>
-    <button tool-selector="circle-measure" class="tool-selector">circle</button>
-    <button tool-selector="crop" class="tool-selector">crop</button>
-    <button tool-selector="windowing" class="tool-selector">windowing</button>
-    <button tool-selector="zoom" class="tool-selector">zoom</button>
-    <button tool-selector="pan" class="tool-selector">pan</button>
-    <button action-trigger="rotate-left" class="action-trigger">rotate left</button>
-    <button action-trigger="rotate-right" class="action-trigger">rotate right</button>
-    <button action-trigger="invert" class="action-trigger">invert</button>
-  </div>
-  <script type="text/javascript" src="app-simple-viewer.js"></script>
-</body>
-
-</html>
\ No newline at end of file
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.ts	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-import wasmApplicationRunner = require('../../../../Platforms/Wasm/wasm-application-runner');
-
-wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSimpleViewer", "/orthanc");
-
-function SelectTool(toolName: string) {
-  var command = {
-    command: "selectTool:" + toolName,
-    commandType: "generic-no-arg-command",
-    args: {
-    }                                                                                                                       
-  };
-  wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
-}
-
-function PerformAction(actionName: string) {
-  var command = {
-    command: "action:" + actionName,
-    commandType: "generic-no-arg-command",
-    args: {
-    }
-  };
-  wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
-}
-
-class SimpleViewerUI {
-
-  private _labelPatientId: HTMLSpanElement;
-  private _labelStudyDescription: HTMLSpanElement;
-
-  public constructor() {
-    // install "SelectTool" handlers
-    document.querySelectorAll("[tool-selector]").forEach((e) => {
-      (e as HTMLButtonElement).addEventListener("click", () => {
-        SelectTool(e.attributes["tool-selector"].value);
-      });
-    });
-
-    // install "PerformAction" handlers
-    document.querySelectorAll("[action-trigger]").forEach((e) => {
-      (e as HTMLButtonElement).addEventListener("click", () => {
-        PerformAction(e.attributes["action-trigger"].value);
-      });
-    });
-
-    // connect all ui elements to members
-    this._labelPatientId = document.getElementById("label-patient-id") as HTMLSpanElement;
-    this._labelStudyDescription = document.getElementById("label-study-description") as HTMLSpanElement;
-  }
-
-  public onAppStatusUpdated(status: any) {
-    this._labelPatientId.innerText = status["patientId"];
-    this._labelStudyDescription.innerText = status["studyDescription"];
-    // this.highlighThumbnail(status["currentInstanceIdInMainViewport"]);
-  }
-
-}
-
-var ui = new SimpleViewerUI();
-
-// this method is called "from the C++ code" when the StoneApplication is updated.
-// it can be used to update the UI of the application
-function UpdateWebApplicationWithString(statusUpdateMessageString: string) {
-  console.log("updating web application with string: ", statusUpdateMessageString);
-  let statusUpdateMessage = JSON.parse(statusUpdateMessageString);
-
-  if ("event" in statusUpdateMessage) {
-    let eventName = statusUpdateMessage["event"];
-    if (eventName == "appStatusUpdated") {
-      ui.onAppStatusUpdated(statusUpdateMessage["data"]);
-    }
-  }
-}
-
-function UpdateWebApplicationWithSerializedMessage(statusUpdateMessageString: string) {
-  console.log("updating web application with serialized message: ", statusUpdateMessageString);
-  console.log("<not supported in the simple viewer!>");
-}
-
-// make it available to other js scripts in the application
-(<any> window).UpdateWebApplicationWithString = UpdateWebApplicationWithString;
-(<any> window).UpdateWebApplicationWithSerializedMessage = UpdateWebApplicationWithSerializedMessage;
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/styles.css	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-html, body {
-    width: 100%;
-    height: 100%;
-    margin: 0px;
-    border: 0;
-    overflow: hidden; /*  Disable scrollbars */
-    display: block;  /* No floating content on sides */
-    background-color: black;
-    color: white;
-    font-family: Arial, Helvetica, sans-serif;
-}
-
-canvas {
-    left:0px;
-    top:0px;
-}
-
-#canvas-group {
-    padding:5px;
-    background-color: grey;
-}
-
-#status-group {
-    padding:5px;
-}
-
-#worklist-group {
-    padding:5px;
-}
-
-.vsol-button {
-    height: 40px;
-}
-
-#thumbnails-group ul li {
-    display: inline;
-    list-style: none;
-}
-
-.thumbnail {
-    width: 100px;
-    height: 100px;
-    padding: 3px;
-}
-
-.thumbnail-selected {
-    border-width: 1px;
-    border-color: red;
-    border-style: solid;
-}
-
-#template-thumbnail-li {
-    display: none !important;
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/SimpleViewer/Wasm/tsconfig-simple-viewer.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-{
-    "extends" : "../../Web/tsconfig-samples",
-    "compilerOptions": {
-    },
-    "include" : [
-        "simple-viewer.ts",
-        "../../build-wasm/ApplicationCommands_generated.ts"
-    ]
-}
--- a/Applications/Samples/Deprecated/SimpleViewerApplicationSingleFile.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,461 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-
-#include "../../../Framework/Deprecated/Layers/CircleMeasureTracker.h"
-#include "../../../Framework/Deprecated/Layers/LineMeasureTracker.h"
-#include "../../../Framework/Deprecated/SmartLoader.h"
-#include "../../../Framework/Deprecated/Widgets/LayoutWidget.h"
-#include "../../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
-#include "../../../Framework/Messages/IObserver.h"
-
-#if ORTHANC_ENABLE_WASM==1
-#include "../../../Platforms/Wasm/WasmPlatformApplicationAdapter.h"
-#include "../../../Platforms/Wasm/Defaults.h"
-#endif
-
-#include <Core/Images/Font.h>
-#include <Core/Logging.h>
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class SimpleViewerApplication :
-      public SampleSingleCanvasWithButtonsApplicationBase,
-      public ObserverBase<SimpleViewerApplication>
-    {
-    private:
-      class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
-      {
-      private:
-        SimpleViewerApplication&  application_;
-
-      public:
-        ThumbnailInteractor(SimpleViewerApplication&  application) :
-          application_(application)
-        {
-        }
-
-        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                            const Deprecated::ViewportGeometry& view,
-                                                            MouseButton button,
-                                                            KeyboardModifiers modifiers,
-                                                            int viewportX,
-                                                            int viewportY,
-                                                            double x,
-                                                            double y,
-                                                            Deprecated::IStatusBar* statusBar,
-                                                            const std::vector<Deprecated::Touch>& displayTouches)
-        {
-          if (button == MouseButton_Left)
-          {
-            statusBar->SetMessage("selected thumbnail " + widget.GetName());
-            std::string seriesId = widget.GetName().substr(strlen("thumbnail-series-"));
-            application_.SelectSeriesInMainViewport(seriesId);
-          }
-          return NULL;
-        }
-
-        virtual void MouseOver(CairoContext& context,
-                               Deprecated::WorldSceneWidget& widget,
-                               const Deprecated::ViewportGeometry& view,
-                               double x,
-                               double y,
-                               Deprecated::IStatusBar* statusBar)
-        {
-        }
-
-        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
-                                MouseWheelDirection direction,
-                                KeyboardModifiers modifiers,
-                                Deprecated::IStatusBar* statusBar)
-        {
-        }
-
-        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
-                                KeyboardKeys key,
-                                char keyChar,
-                                KeyboardModifiers modifiers,
-                                Deprecated::IStatusBar* statusBar)
-        {
-        }
-      };
-
-      class MainWidgetInteractor : public Deprecated::IWorldSceneInteractor
-      {
-      private:
-        SimpleViewerApplication&  application_;
-        
-      public:
-        MainWidgetInteractor(SimpleViewerApplication&  application) :
-          application_(application)
-        {
-        }
-        
-        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                            const Deprecated::ViewportGeometry& view,
-                                                            MouseButton button,
-                                                            KeyboardModifiers modifiers,
-                                                            int viewportX,
-                                                            int viewportY,
-                                                            double x,
-                                                            double y,
-                                                            Deprecated::IStatusBar* statusBar,
-                                                            const std::vector<Deprecated::Touch>& displayTouches)
-        {
-          if (button == MouseButton_Left)
-          {
-            if (application_.currentTool_ == Tool_LineMeasure)
-            {
-              return new Deprecated::LineMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
-                                            x, y, 255, 0, 0, application_.GetFont());
-            }
-            else if (application_.currentTool_ == Tool_CircleMeasure)
-            {
-              return new Deprecated::CircleMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
-                                              x, y, 255, 0, 0, application_.GetFont());
-            }
-          }
-          return NULL;
-        }
-
-        virtual void MouseOver(CairoContext& context,
-                               Deprecated::WorldSceneWidget& widget,
-                               const Deprecated::ViewportGeometry& view,
-                               double x,
-                               double y,
-                               Deprecated::IStatusBar* statusBar)
-        {
-          if (statusBar != NULL)
-          {
-            Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
-            
-            char buf[64];
-            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
-                    p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
-            statusBar->SetMessage(buf);
-          }
-        }
-
-        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
-                                MouseWheelDirection direction,
-                                KeyboardModifiers modifiers,
-                                Deprecated::IStatusBar* statusBar)
-        {
-        }
-
-        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
-                                KeyboardKeys key,
-                                char keyChar,
-                                KeyboardModifiers modifiers,
-                                Deprecated::IStatusBar* statusBar)
-        {
-          switch (keyChar)
-          {
-            case 's':
-              widget.FitContent();
-              break;
-
-            case 'l':
-              application_.currentTool_ = Tool_LineMeasure;
-              break;
-
-            case 'c':
-              application_.currentTool_ = Tool_CircleMeasure;
-              break;
-
-            default:
-              break;
-          }
-        }
-      };
-
-
-#if ORTHANC_ENABLE_WASM==1
-      class SimpleViewerApplicationAdapter : public WasmPlatformApplicationAdapter
-      {
-        SimpleViewerApplication&  viewerApplication_;
-
-      public:
-        SimpleViewerApplicationAdapter(SimpleViewerApplication& application)
-          : WasmPlatformApplicationAdapter(application),
-            viewerApplication_(application)
-        {
-        }
-
-        virtual void HandleSerializedMessageFromWeb(std::string& output, const std::string& input) 
-        {
-          if (input == "select-tool:line-measure")
-          {
-            viewerApplication_.currentTool_ = Tool_LineMeasure;
-            NotifyStatusUpdateFromCppToWebWithString("currentTool=line-measure");
-          }
-          else if (input == "select-tool:circle-measure")
-          {
-            viewerApplication_.currentTool_ = Tool_CircleMeasure;
-            NotifyStatusUpdateFromCppToWebWithString("currentTool=circle-measure");
-          }
-
-          output = "ok";
-        }
-
-        virtual void NotifySerializedMessageFromCppToWeb(const std::string& statusUpdateMessage) 
-        {
-          UpdateStoneApplicationStatusFromCppWithSerializedMessage(statusUpdateMessage.c_str());
-        }
-
-        virtual void NotifyStatusUpdateFromCppToWebWithString(const std::string& statusUpdateMessage) 
-        {
-          UpdateStoneApplicationStatusFromCppWithString(statusUpdateMessage.c_str());
-        }
-
-      };
-#endif
-      enum Tool {
-        Tool_LineMeasure,
-        Tool_CircleMeasure
-      };
-
-      Tool                                 currentTool_;
-      std::unique_ptr<MainWidgetInteractor>  mainWidgetInteractor_;
-      std::unique_ptr<ThumbnailInteractor>   thumbnailInteractor_;
-      Deprecated::LayoutWidget*                        mainLayout_;
-      Deprecated::LayoutWidget*                        thumbnailsLayout_;
-      std::vector<boost::shared_ptr<Deprecated::SliceViewerWidget> >      thumbnails_;
-
-      std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
-      std::map<std::string, Json::Value> seriesTags_;
-
-      unsigned int                         currentInstanceIndex_;
-      Deprecated::WidgetViewport*        wasmViewport1_;
-      Deprecated::WidgetViewport*        wasmViewport2_;
-
-      Deprecated::IStatusBar*                          statusBar_;
-      std::unique_ptr<Deprecated::SmartLoader>           smartLoader_;
-
-      Orthanc::Font                        font_;
-
-    public:
-      SimpleViewerApplication() :
-        currentTool_(Tool_LineMeasure),
-        mainLayout_(NULL),
-        currentInstanceIndex_(0),
-        wasmViewport1_(NULL),
-        wasmViewport2_(NULL)
-      {
-        font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
-//        DeclareIgnoredMessage(MessageType_Widget_ContentChanged);
-      }
-
-      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("studyId", boost::program_options::value<std::string>(),
-           "Orthanc ID of the study")
-          ;
-
-        options.add(generic);
-      }
-
-      virtual void Initialize(StoneApplicationContext* context,
-                              Deprecated::IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        context_ = context;
-        statusBar_ = &statusBar;
-
-        {// initialize viewports and layout
-          mainLayout_ = new Deprecated::LayoutWidget("main-layout");
-          mainLayout_->SetPadding(10);
-          mainLayout_->SetBackgroundCleared(true);
-          mainLayout_->SetBackgroundColor(0, 0, 0);
-          mainLayout_->SetHorizontal();
-
-          boost::shared_ptr<Deprecated::LayoutWidget> thumbnailsLayout_(new Deprecated::LayoutWidget("thumbnail-layout"));
-          thumbnailsLayout_->SetPadding(10);
-          thumbnailsLayout_->SetBackgroundCleared(true);
-          thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
-          thumbnailsLayout_->SetVertical();
-
-          boost::shared_ptr<Deprecated::SliceViewerWidget> widget
-            (new Deprecated::SliceViewerWidget("main-viewport"));
-          SetCentralWidget(widget);
-          //mainWidget_->RegisterObserver(*this);
-
-          // hierarchy
-          mainLayout_->AddWidget(thumbnailsLayout_);
-          mainLayout_->AddWidget(widget);
-
-          // sources
-          smartLoader_.reset(new Deprecated::SmartLoader(context->GetOrthancApiClient()));
-          smartLoader_->SetImageQuality(Deprecated::SliceImageQuality_FullPam);
-
-          mainLayout_->SetTransmitMouseOver(true);
-          mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
-          widget->SetInteractor(*mainWidgetInteractor_);
-          thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
-        }
-
-        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
-        statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport");
-
-
-        if (parameters.count("studyId") < 1)
-        {
-          LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
-          context->GetOrthancApiClient()->GetJsonAsync(
-            "/studies",
-            new Deprecated::DeprecatedCallable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-            (GetSharedObserver(), &SimpleViewerApplication::OnStudyListReceived));
-        }
-        else
-        {
-          SelectStudy(parameters["studyId"].as<std::string>());
-        }
-      }
-
-      void OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
-      {
-        const Json::Value& response = message.GetJson();
-
-        if (response.isArray() &&
-            response.size() >= 1)
-        {
-          SelectStudy(response[0].asString());
-        }
-      }
-      
-      void OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
-      {
-        const Json::Value& response = message.GetJson();
-
-        if (response.isObject() && response["Series"].isArray())
-        {
-          for (size_t i=0; i < response["Series"].size(); i++)
-          {
-            context_->GetOrthancApiClient()->GetJsonAsync(
-              "/series/" + response["Series"][(int)i].asString(),
-              new Deprecated::DeprecatedCallable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-              (GetSharedObserver(), &SimpleViewerApplication::OnSeriesReceived));
-          }
-        }
-      }
-
-      void OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
-      {
-        const Json::Value& response = message.GetJson();
-
-        if (response.isObject() &&
-            response["Instances"].isArray() &&
-            response["Instances"].size() > 0)
-        {
-          // keep track of all instances IDs
-          const std::string& seriesId = response["ID"].asString();
-          seriesTags_[seriesId] = response;
-          instancesIdsPerSeriesId_[seriesId] = std::vector<std::string>();
-          for (size_t i = 0; i < response["Instances"].size(); i++)
-          {
-            const std::string& instanceId = response["Instances"][static_cast<int>(i)].asString();
-            instancesIdsPerSeriesId_[seriesId].push_back(instanceId);
-          }
-
-          // load the first instance in the thumbnail
-          LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
-
-          // if this is the first thumbnail loaded, load the first instance in the mainWidget
-          Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget());
-          if (widget.GetLayerCount() == 0)
-          {
-            smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
-          }
-        }
-      }
-
-      void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
-      {
-        LOG(INFO) << "Loading thumbnail for series " << seriesId;
-        boost::shared_ptr<Deprecated::SliceViewerWidget> thumbnailWidget(new Deprecated::SliceViewerWidget("thumbnail-series-" + seriesId));
-        thumbnails_.push_back(thumbnailWidget);
-        thumbnailsLayout_->AddWidget(thumbnailWidget);
-        Register<Deprecated::SliceViewerWidget::GeometryChangedMessage>(*thumbnailWidget, &SimpleViewerApplication::OnWidgetGeometryChanged);
-        smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
-        thumbnailWidget->SetInteractor(*thumbnailInteractor_);
-      }
-
-      void SelectStudy(const std::string& studyId)
-      {
-        LOG(INFO) << "Selecting study: " << studyId;
-        context_->GetOrthancApiClient()->GetJsonAsync(
-          "/studies/" + studyId, new Deprecated::DeprecatedCallable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-          (GetSharedObserver(), &SimpleViewerApplication::OnStudyReceived));
-      }
-
-      void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
-      {
-        // TODO: The "const_cast" could probably be replaced by "mainWidget"
-        const_cast<Deprecated::SliceViewerWidget&>(message.GetOrigin()).FitContent();
-      }
-
-      void SelectSeriesInMainViewport(const std::string& seriesId)
-      {
-        Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget());
-        smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
-      }
-
-      const Orthanc::Font& GetFont() const
-      {
-        return font_;
-      }
-      
-      virtual void OnPushButton1Clicked() {}
-      virtual void OnPushButton2Clicked() {}
-      virtual void OnTool1Clicked() { currentTool_ = Tool_LineMeasure;}
-      virtual void OnTool2Clicked() { currentTool_ = Tool_CircleMeasure;}
-
-      virtual void GetButtonNames(std::string& pushButton1,
-                                  std::string& pushButton2,
-                                  std::string& tool1,
-                                  std::string& tool2)
-      {
-        tool1 = "line";
-        tool2 = "circle";
-        pushButton1 = "action1";
-        pushButton2 = "action2";
-      }
-
-#if ORTHANC_ENABLE_WASM==1
-      virtual void InitializeWasm()
-      {
-        AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
-        AttachWidgetToWasmViewport("canvas2", widget);
-      }
-#endif
-
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/SingleFrameApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,268 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-
-#include "../../../Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h"
-#include "../../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/math/constants/constants.hpp>
-
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class SingleFrameApplication :
-      public SampleSingleCanvasApplicationBase,
-      public ObserverBase<SingleFrameApplication>
-    {
-    private:
-      class Interactor : public Deprecated::IWorldSceneInteractor
-      {
-      private:
-        SingleFrameApplication&  application_;
-        
-      public:
-        Interactor(SingleFrameApplication&  application) :
-          application_(application)
-        {
-        }
-        
-        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
-                                                                        const Deprecated::ViewportGeometry& view,
-                                                                        MouseButton button,
-                                                                        KeyboardModifiers modifiers,
-                                                                        int viewportX,
-                                                                        int viewportY,
-                                                                        double x,
-                                                                        double y,
-                                                                        Deprecated::IStatusBar* statusBar,
-                                                                        const std::vector<Deprecated::Touch>& displayTouches)
-        {
-          return NULL;
-        }
-
-        virtual void MouseOver(CairoContext& context,
-                               Deprecated::WorldSceneWidget& widget,
-                               const Deprecated::ViewportGeometry& view,
-                               double x,
-                               double y,
-                               Deprecated::IStatusBar* statusBar)
-        {
-          if (statusBar != NULL)
-          {
-            Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
-            
-            char buf[64];
-            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", 
-                    p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
-            statusBar->SetMessage(buf);
-          }
-        }
-
-        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
-                                MouseWheelDirection direction,
-                                KeyboardModifiers modifiers,
-                                Deprecated::IStatusBar* statusBar)
-        {
-          int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
-          
-          switch (direction)
-          {
-            case MouseWheelDirection_Up:
-              application_.OffsetSlice(-scale);
-              break;
-
-            case MouseWheelDirection_Down:
-              application_.OffsetSlice(scale);
-              break;
-
-            default:
-              break;
-          }
-        }
-
-        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
-                                KeyboardKeys key,
-                                char keyChar,
-                                KeyboardModifiers modifiers,
-                                Deprecated::IStatusBar* statusBar)
-        {
-          switch (keyChar)
-          {
-            case 's':
-              widget.FitContent();
-              break;
-
-            default:
-              break;
-          }
-        }
-      };
-
-
-      void OffsetSlice(int offset)
-      {
-        if (source_)
-        {
-          int slice = static_cast<int>(slice_) + offset;
-
-          if (slice < 0)
-          {
-            slice = 0;
-          }
-
-          if (slice >= static_cast<int>(source_->GetSlicesCount()))
-          {
-            slice = static_cast<int>(source_->GetSlicesCount()) - 1;
-          }
-
-          if (slice != static_cast<int>(slice_)) 
-          {
-            SetSlice(slice);
-          }   
-        }
-      }
-
-
-      void SetSlice(size_t index)
-      {
-        if (source_ &&
-            index < source_->GetSlicesCount())
-        {
-          slice_ = static_cast<unsigned int>(index);
-          
-#if 1
-          widget_->SetSlice(source_->GetSlice(slice_).GetGeometry());
-#else
-          // TEST for scene extents - Rotate the axes
-          double a = 15.0 / 180.0 * boost::math::constants::pi<double>();
-
-#if 1
-          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
-          Vector y; GeometryToolbox::AssignVector(y, -sin(a), cos(a), 0);
-#else
-          // Flip the normal
-          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
-          Vector y; GeometryToolbox::AssignVector(y, sin(a), -cos(a), 0);
-#endif
-          
-          SliceGeometry s(source_->GetSlice(slice_).GetGeometry().GetOrigin(), x, y);
-          widget_->SetSlice(s);
-#endif
-        }
-      }
-        
-      
-      void OnMainWidgetGeometryReady(const Deprecated::IVolumeSlicer::GeometryReadyMessage& message)
-      {
-        // Once the geometry of the series is downloaded from Orthanc,
-        // display its middle slice, and adapt the viewport to fit this
-        // slice
-        if (source_ &&
-            source_.get() == &message.GetOrigin())
-        {
-          SetSlice(source_->GetSlicesCount() / 2);
-        }
-
-        widget_->FitContent();
-      }
-
-      boost::shared_ptr<Deprecated::SliceViewerWidget>  widget_;
-      std::unique_ptr<Interactor>         mainWidgetInteractor_;
-      boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> source_;
-      unsigned int                      slice_;
-
-    public:
-      SingleFrameApplication() :
-        slice_(0)
-      {
-      }
-      
-      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("instance", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the instance")
-          ("frame", boost::program_options::value<unsigned int>()->default_value(0),
-           "Number of the frame, for multi-frame DICOM instances")
-          ("smooth", boost::program_options::value<bool>()->default_value(true), 
-           "Enable bilinear interpolation to smooth the image")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(StoneApplicationContext* context,
-                              Deprecated::IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        context_ = context;
-
-        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
-
-        if (parameters.count("instance") != 1)
-        {
-          LOG(ERROR) << "The instance ID is missing";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::string instance = parameters["instance"].as<std::string>();
-        int frame = parameters["frame"].as<unsigned int>();
-
-        widget_.reset(new Deprecated::SliceViewerWidget("main-widget"));
-        SetCentralWidget(widget_);
-
-        boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer);
-        layer->Connect(context->GetOrthancApiClient());
-        source_ = layer;
-
-        layer->LoadFrame(instance, frame);
-        Register<Deprecated::IVolumeSlicer::GeometryReadyMessage>(*layer, &SingleFrameApplication::OnMainWidgetGeometryReady);
-        widget_->AddLayer(layer);
-
-        Deprecated::RenderStyle s;
-
-        if (parameters["smooth"].as<bool>())
-        {
-          s.interpolation_ = ImageInterpolation_Bilinear;
-        }
-
-        widget_->SetLayerStyle(0, s);
-        widget_->SetTransmitMouseOver(true);
-
-        mainWidgetInteractor_.reset(new Interactor(*this));
-        widget_->SetInteractor(*mainWidgetInteractor_);
-      }
-    };
-
-
-  }
-}
--- a/Applications/Samples/Deprecated/SingleFrameEditorApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,531 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-
-#include "../../../Framework/Radiography/RadiographyLayerCropTracker.h"
-#include "../../../Framework/Radiography/RadiographyLayerMaskTracker.h"
-#include "../../../Framework/Radiography/RadiographyLayerMoveTracker.h"
-#include "../../../Framework/Radiography/RadiographyLayerResizeTracker.h"
-#include "../../../Framework/Radiography/RadiographyLayerRotateTracker.h"
-#include "../../../Framework/Radiography/RadiographyMaskLayer.h"
-#include "../../../Framework/Radiography/RadiographyScene.h"
-#include "../../../Framework/Radiography/RadiographySceneCommand.h"
-#include "../../../Framework/Radiography/RadiographySceneReader.h"
-#include "../../../Framework/Radiography/RadiographySceneWriter.h"
-#include "../../../Framework/Radiography/RadiographyWidget.h"
-#include "../../../Framework/Radiography/RadiographyWindowingTracker.h"
-#include "../../../Framework/Toolbox/TextRenderer.h"
-
-#include <Core/HttpClient.h>
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <Core/Images/PngWriter.h>
-#include <Core/Images/PngReader.h>
-
-
-// Export using PAM is faster than using PNG, but requires Orthanc
-// core >= 1.4.3
-#define EXPORT_USING_PAM  1
-
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class RadiographyEditorInteractor :
-        public Deprecated::IWorldSceneInteractor,
-        public ObserverBase<RadiographyEditorInteractor>
-    {
-    private:
-      enum Tool
-      {
-        Tool_Move,
-        Tool_Rotate,
-        Tool_Crop,
-        Tool_Resize,
-        Tool_Mask,
-        Tool_Windowing
-      };
-
-
-      StoneApplicationContext*  context_;
-      UndoRedoStack             undoRedoStack_;
-      Tool                      tool_;
-      RadiographyMaskLayer*     maskLayer_;
-
-
-      static double GetHandleSize()
-      {
-        return 10.0;
-      }
-
-
-    public:
-      RadiographyEditorInteractor() :
-        context_(NULL),
-        tool_(Tool_Move),
-        maskLayer_(NULL)
-      {
-      }
-
-      void SetContext(StoneApplicationContext& context)
-      {
-        context_ = &context;
-      }
-
-      void SetMaskLayer(RadiographyMaskLayer* maskLayer)
-      {
-        maskLayer_ = maskLayer;
-      }
-      virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& worldWidget,
-                                                                      const Deprecated::ViewportGeometry& view,
-                                                                      MouseButton button,
-                                                                      KeyboardModifiers modifiers,
-                                                                      int viewportX,
-                                                                      int viewportY,
-                                                                      double x,
-                                                                      double y,
-                                                                      Deprecated::IStatusBar* statusBar,
-                                                                      const std::vector<Deprecated::Touch>& displayTouches)
-      {
-        RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
-
-        if (button == MouseButton_Left)
-        {
-          size_t selected;
-
-          if (tool_ == Tool_Windowing)
-          {
-            return new RadiographyWindowingTracker(
-                  undoRedoStack_,
-                  widget.GetScene(),
-                  widget,
-                  OrthancStone::ImageInterpolation_Nearest,
-                  viewportX, viewportY,
-                  RadiographyWindowingTracker::Action_DecreaseWidth,
-                  RadiographyWindowingTracker::Action_IncreaseWidth,
-                  RadiographyWindowingTracker::Action_DecreaseCenter,
-                  RadiographyWindowingTracker::Action_IncreaseCenter);
-          }
-          else if (!widget.LookupSelectedLayer(selected))
-          {
-            // No layer is currently selected
-            size_t layer;
-            if (widget.GetScene().LookupLayer(layer, x, y))
-            {
-              widget.Select(layer);
-            }
-
-            return NULL;
-          }
-          else if (tool_ == Tool_Crop ||
-                   tool_ == Tool_Resize ||
-                   tool_ == Tool_Mask)
-          {
-            RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
-            
-            ControlPoint controlPoint;
-            if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize()))
-            {
-              switch (tool_)
-              {
-              case Tool_Crop:
-                return new RadiographyLayerCropTracker
-                    (undoRedoStack_, widget.GetScene(), view, selected, controlPoint);
-
-              case Tool_Mask:
-                return new RadiographyLayerMaskTracker
-                    (undoRedoStack_, widget.GetScene(), view, selected, controlPoint);
-
-              case Tool_Resize:
-                return new RadiographyLayerResizeTracker
-                    (undoRedoStack_, widget.GetScene(), selected, controlPoint,
-                     (modifiers & KeyboardModifiers_Shift));
-
-              default:
-                throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-              }
-            }
-            else
-            {
-              size_t layer;
-
-              if (widget.GetScene().LookupLayer(layer, x, y))
-              {
-                widget.Select(layer);
-              }
-              else
-              {
-                widget.Unselect();
-              }
-
-              return NULL;
-            }
-          }
-          else
-          {
-            size_t layer;
-
-            if (widget.GetScene().LookupLayer(layer, x, y))
-            {
-              if (layer == selected)
-              {
-                switch (tool_)
-                {
-                case Tool_Move:
-                  return new RadiographyLayerMoveTracker
-                      (undoRedoStack_, widget.GetScene(), layer, x, y,
-                       (modifiers & KeyboardModifiers_Shift));
-
-                case Tool_Rotate:
-                  return new RadiographyLayerRotateTracker
-                      (undoRedoStack_, widget.GetScene(), view, layer, x, y,
-                       (modifiers & KeyboardModifiers_Shift));
-
-                default:
-                  break;
-                }
-
-                return NULL;
-              }
-              else
-              {
-                widget.Select(layer);
-                return NULL;
-              }
-            }
-            else
-            {
-              widget.Unselect();
-              return NULL;
-            }
-          }
-        }
-        else
-        {
-          return NULL;
-        }
-        return NULL;
-      }
-
-      virtual void MouseOver(CairoContext& context,
-                             Deprecated::WorldSceneWidget& worldWidget,
-                             const Deprecated::ViewportGeometry& view,
-                             double x,
-                             double y,
-                             Deprecated::IStatusBar* statusBar)
-      {
-        RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
-
-#if 0
-        if (statusBar != NULL)
-        {
-          char buf[64];
-          sprintf(buf, "X = %.02f Y = %.02f (in cm)", x / 10.0, y / 10.0);
-          statusBar->SetMessage(buf);
-        }
-#endif
-
-        size_t selected;
-
-        if (widget.LookupSelectedLayer(selected) &&
-            (tool_ == Tool_Crop ||
-             tool_ == Tool_Resize ||
-             tool_ == Tool_Mask))
-        {
-          RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
-
-          ControlPoint controlPoint;
-          if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize()))
-          {
-            double z = 1.0 / view.GetZoom();
-
-            context.SetSourceColor(255, 0, 0);
-            cairo_t* cr = context.GetObject();
-            cairo_set_line_width(cr, 2.0 * z);
-            cairo_move_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
-            cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
-            cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y + GetHandleSize() * z);
-            cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y + GetHandleSize() * z);
-            cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
-            cairo_stroke(cr);
-          }
-        }
-      }
-
-      virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
-                              MouseWheelDirection direction,
-                              KeyboardModifiers modifiers,
-                              Deprecated::IStatusBar* statusBar)
-      {
-      }
-
-      virtual void KeyPressed(Deprecated::WorldSceneWidget& worldWidget,
-                              KeyboardKeys key,
-                              char keyChar,
-                              KeyboardModifiers modifiers,
-                              Deprecated::IStatusBar* statusBar)
-      {
-        RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
-
-        switch (keyChar)
-        {
-        case 'a':
-          widget.FitContent();
-          break;
-
-        case 'c':
-          tool_ = Tool_Crop;
-          break;
-
-        case 'm':
-          tool_ = Tool_Mask;
-          widget.Select(1);
-          break;
-
-        case 'd':
-        {
-          // dump to json and reload
-          Json::Value snapshot;
-          RadiographySceneWriter writer;
-          writer.Write(snapshot, widget.GetScene());
-
-          LOG(INFO) << "JSON export was successful: "
-                    << snapshot.toStyledString();
-
-          boost::shared_ptr<RadiographyScene> scene(new RadiographyScene);
-          RadiographySceneReader reader(*scene, *context_->GetOrthancApiClient());
-          reader.Read(snapshot);
-
-          widget.SetScene(scene);
-        };break;
-
-        case 'e':
-        {
-          Orthanc::DicomMap tags;
-
-          // Minimal set of tags to generate a valid CR image
-          tags.SetValue(Orthanc::DICOM_TAG_ACCESSION_NUMBER, "NOPE", false);
-          tags.SetValue(Orthanc::DICOM_TAG_BODY_PART_EXAMINED, "PELVIS", false);
-          tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1", false);
-          //tags.SetValue(Orthanc::DICOM_TAG_LATERALITY, "", false);
-          tags.SetValue(Orthanc::DICOM_TAG_MANUFACTURER, "OSIMIS", false);
-          tags.SetValue(Orthanc::DICOM_TAG_MODALITY, "CR", false);
-          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_BIRTH_DATE, "20000101", false);
-          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ID, "hello", false);
-          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_NAME, "HELLO^WORLD", false);
-          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ORIENTATION, "", false);
-          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_SEX, "M", false);
-          tags.SetValue(Orthanc::DICOM_TAG_REFERRING_PHYSICIAN_NAME, "HOUSE^MD", false);
-          tags.SetValue(Orthanc::DICOM_TAG_SERIES_NUMBER, "1", false);
-          tags.SetValue(Orthanc::DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false);
-          tags.SetValue(Orthanc::DICOM_TAG_STUDY_ID, "STUDY", false);
-          tags.SetValue(Orthanc::DICOM_TAG_VIEW_POSITION, "", false);
-
-          if (context_ != NULL)
-          {
-            widget.GetScene().ExportDicom(*context_->GetOrthancApiClient(),
-                                          tags, std::string(), 0.1, 0.1, widget.IsInverted(),
-                                          false /* autoCrop */, widget.GetInterpolation(), EXPORT_USING_PAM);
-          }
-
-          break;
-        }
-
-        case 'i':
-          widget.SwitchInvert();
-          break;
-
-        case 't':
-          tool_ = Tool_Move;
-          break;
-
-        case 'n':
-        {
-          switch (widget.GetInterpolation())
-          {
-          case ImageInterpolation_Nearest:
-            LOG(INFO) << "Switching to bilinear interpolation";
-            widget.SetInterpolation(ImageInterpolation_Bilinear);
-            break;
-
-          case ImageInterpolation_Bilinear:
-            LOG(INFO) << "Switching to nearest neighbor interpolation";
-            widget.SetInterpolation(ImageInterpolation_Nearest);
-            break;
-
-          default:
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-          }
-          
-          break;
-        }
-
-        case 'r':
-          tool_ = Tool_Rotate;
-          break;
-
-        case 's':
-          tool_ = Tool_Resize;
-          break;
-
-        case 'w':
-          tool_ = Tool_Windowing;
-          break;
-
-        case 'y':
-          if (modifiers & KeyboardModifiers_Control)
-          {
-            undoRedoStack_.Redo();
-            widget.NotifyContentChanged();
-          }
-          break;
-
-        case 'z':
-          if (modifiers & KeyboardModifiers_Control)
-          {
-            undoRedoStack_.Undo();
-            widget.NotifyContentChanged();
-          }
-          break;
-
-        default:
-          break;
-        }
-      }
-    };
-
-
-
-    class SingleFrameEditorApplication :
-        public SampleSingleCanvasApplicationBase,
-        public IObserver
-    {
-    private:
-      boost::shared_ptr<RadiographyScene>   scene_;
-      RadiographyEditorInteractor           interactor_;
-      RadiographyMaskLayer*                 maskLayer_;
-
-    public:
-      virtual ~SingleFrameEditorApplication()
-      {
-        LOG(WARNING) << "Destroying the application";
-      }
-      
-      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-            ("instance", boost::program_options::value<std::string>(),
-             "Orthanc ID of the instance")
-            ("frame", boost::program_options::value<unsigned int>()->default_value(0),
-             "Number of the frame, for multi-frame DICOM instances")
-            ;
-
-        options.add(generic);
-      }
-
-      virtual void Initialize(StoneApplicationContext* context,
-                              Deprecated::IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        context_ = context;
-        interactor_.SetContext(*context);
-
-        statusBar.SetMessage("Use the key \"a\" to reinitialize the layout");
-        statusBar.SetMessage("Use the key \"c\" to crop");
-        statusBar.SetMessage("Use the key \"e\" to export DICOM to the Orthanc server");
-        statusBar.SetMessage("Use the key \"f\" to switch full screen");
-        statusBar.SetMessage("Use the key \"i\" to invert contrast");
-        statusBar.SetMessage("Use the key \"m\" to modify the mask");
-        statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation");
-        statusBar.SetMessage("Use the key \"r\" to rotate objects");
-        statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM layers)");
-        statusBar.SetMessage("Use the key \"t\" to move (translate) objects");
-        statusBar.SetMessage("Use the key \"w\" to change windowing");
-        
-        statusBar.SetMessage("Use the key \"ctrl-z\" to undo action");
-        statusBar.SetMessage("Use the key \"ctrl-y\" to redo action");
-
-        if (parameters.count("instance") != 1)
-        {
-          LOG(ERROR) << "The instance ID is missing";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::string instance = parameters["instance"].as<std::string>();
-        //int frame = parameters["frame"].as<unsigned int>();
-
-        scene_.reset(new RadiographyScene);
-        
-        RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(*context->GetOrthancApiClient(), instance, 0, false, NULL);
-        //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0);
-        // = scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false, NULL);
-
-#if !defined(ORTHANC_ENABLE_WASM) || ORTHANC_ENABLE_WASM != 1
-        Orthanc::HttpClient::ConfigureSsl(true, "/etc/ssl/certs/ca-certificates.crt");
-#endif
-        
-        //scene_->LoadDicomWebFrame(context->GetWebService());
-        
-        std::vector<Orthanc::ImageProcessing::ImagePoint> mask;
-        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1100, 100));
-        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1100, 1000));
-        mask.push_back(Orthanc::ImageProcessing::ImagePoint(2000, 1000));
-        mask.push_back(Orthanc::ImageProcessing::ImagePoint(2200, 150));
-        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1500, 550));
-        maskLayer_ = dynamic_cast<RadiographyMaskLayer*>(&(scene_->LoadMask(mask, dynamic_cast<RadiographyDicomLayer&>(dicomLayer), 128.0f, NULL)));
-        interactor_.SetMaskLayer(maskLayer_);
-
-        {
-          std::unique_ptr<Orthanc::ImageAccessor> renderedTextAlpha(TextRenderer::Render(Orthanc::EmbeddedResources::UBUNTU_FONT, 100,
-                                                                                    "%öÇaA&#"));
-          RadiographyLayer& layer = scene_->LoadAlphaBitmap(renderedTextAlpha.release(), NULL);
-          dynamic_cast<RadiographyAlphaLayer&>(layer).SetForegroundValue(200.0f * 256.0f);
-        }
-
-        {
-          RadiographyTextLayer::RegisterFont("ubuntu", Orthanc::EmbeddedResources::UBUNTU_FONT);
-          RadiographyLayer& layer = scene_->LoadText("Hello\nworld", "ubuntu", 20, 128, NULL, false);
-          layer.SetResizeable(true);
-        }
-        
-        {
-          RadiographyLayer& layer = scene_->LoadTestBlock(100, 50, NULL);
-          layer.SetResizeable(true);
-          layer.SetPan(0, 200);
-        }
-        
-        boost::shared_ptr<RadiographyWidget> widget(new RadiographyWidget(scene_, "main-widget"));
-        widget->SetTransmitMouseOver(true);
-        widget->SetInteractor(interactor_);
-        SetCentralWidget(widget);
-
-        //scene_->SetWindowing(128, 256);
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/SingleVolumeApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-#include "../../../Framework/dev.h"
-#include "../../../Framework/Layers/LineMeasureTracker.h"
-#include "../../../Framework/Layers/CircleMeasureTracker.h"
-
-#include <Core/Toolbox.h>
-#include <Core/Logging.h>
-
-#include <Plugins/Samples/Common/OrthancHttpConnection.h>   // TODO REMOVE
-#include "../../../Framework/Layers/DicomStructureSetSlicer.h"   // TODO REMOVE
-#include "../../../Framework/Toolbox/MessagingToolbox.h"   // TODO REMOVE
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class SingleVolumeApplication : public SampleApplicationBase
-    {
-    private:
-      class Interactor : public VolumeImageInteractor
-      {
-      private:
-        SliceViewerWidget&  widget_;
-        size_t        layer_;
-        
-      protected:
-        virtual void NotifySliceContentChange(const ISlicedVolume& volume,
-                                       const size_t& sliceIndex,
-                                       const Slice& slice)
-        {
-          const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume);
-
-          RenderStyle s = widget_.GetLayerStyle(layer_);
-
-          if (image.FitWindowingToRange(s, slice.GetConverter()))
-          {
-            //printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
-            widget_.SetLayerStyle(layer_, s);
-          }
-        }
-
-        virtual void MouseOver(CairoContext& context,
-                               WorldSceneWidget& widget,
-                               const ViewportGeometry& view,
-                               double x,
-                               double y,
-                               IStatusBar* statusBar)
-        {
-          const SliceViewerWidget& w = dynamic_cast<const SliceViewerWidget&>(widget);
-          Vector p = w.GetSlice().MapSliceToWorldCoordinates(x, y);
-          printf("%f %f %f\n", p[0], p[1], p[2]);
-        }
-      
-      public:
-        Interactor(OrthancVolumeImage& volume,
-                   SliceViewerWidget& widget,
-                   VolumeProjection projection,
-                   size_t layer) :
-          VolumeImageInteractor(volume, widget, projection),
-          widget_(widget),
-          layer_(layer)
-        {
-        }
-      };
-
-
-    public:
-      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("series", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the series")
-          ("instance", boost::program_options::value<std::string>(), 
-           "Orthanc ID of a multi-frame instance that describes a 3D volume")
-          ("threads", boost::program_options::value<unsigned int>()->default_value(3), 
-           "Number of download threads")
-          ("projection", boost::program_options::value<std::string>()->default_value("axial"), 
-           "Projection of interest (can be axial, sagittal or coronal)")
-          ("reverse", boost::program_options::value<bool>()->default_value(false), 
-           "Reverse the normal direction of the volume")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        if (parameters.count("series") > 1 ||
-            parameters.count("instance") > 1)
-        {
-          LOG(ERROR) << "Only one series or instance is allowed";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        if (parameters.count("series") == 1 &&
-            parameters.count("instance") == 1)
-        {
-          LOG(ERROR) << "Cannot specify both a series and an instance";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::string series;
-        if (parameters.count("series") == 1)
-        {
-          series = parameters["series"].as<std::string>();
-        }
-        
-        std::string instance;
-        if (parameters.count("instance") == 1)
-        {
-          instance = parameters["instance"].as<std::string>();
-        }
-        
-        if (series.empty() &&
-            instance.empty())
-        {
-          LOG(ERROR) << "The series ID or instance ID is missing";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        //unsigned int threads = parameters["threads"].as<unsigned int>();
-        //bool reverse = parameters["reverse"].as<bool>();
-
-        std::string tmp = parameters["projection"].as<std::string>();
-        Orthanc::Toolbox::ToLowerCase(tmp);
-
-        VolumeProjection projection;
-        if (tmp == "axial")
-        {
-          projection = VolumeProjection_Axial;
-        }
-        else if (tmp == "sagittal")
-        {
-          projection = VolumeProjection_Sagittal;
-        }
-        else if (tmp == "coronal")
-        {
-          projection = VolumeProjection_Coronal;
-        }
-        else
-        {
-          LOG(ERROR) << "Unknown projection: " << tmp;
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::unique_ptr<SliceViewerWidget> widget(new SliceViewerWidget);
-
-#if 1
-        std::unique_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService(), true));
-        if (series.empty())
-        {
-          volume->ScheduleLoadInstance(instance);
-        }
-        else
-        {
-          volume->ScheduleLoadSeries(series);
-        }
-
-        widget->AddLayer(new VolumeImageMPRSlicer(*volume));
-
-        context_->AddInteractor(new Interactor(*volume, *widget, projection, 0));
-        context_->AddSlicedVolume(volume.release());
-
-        if (1)
-        {
-          RenderStyle s;
-          //s.drawGrid_ = true;
-          s.alpha_ = 1;
-          s.windowing_ = ImageWindowing_Bone;
-          widget->SetLayerStyle(0, s);
-        }
-        else
-        {
-          RenderStyle s;
-          s.alpha_ = 1;
-          s.applyLut_ = true;
-          s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
-          s.interpolation_ = ImageInterpolation_Bilinear;
-          widget->SetLayerStyle(0, s);
-        }
-#else
-        std::unique_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context_->GetWebService(), false));
-        //ct->ScheduleLoadSeries("15a6f44a-ac7b88fe-19c462d9-dddd918e-b01550d8");  // 0178023P
-        //ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
-        //ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");  // IBA
-        //ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0");  // 0522c0001 TCIA
-        ct->ScheduleLoadSeries("295e8a13-dfed1320-ba6aebb2-9a13e20f-1b3eb953");  // Captain
-        
-        std::unique_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context_->GetWebService(), true));
-        //pet->ScheduleLoadSeries("48d2997f-8e25cd81-dd715b64-bd79cdcc-e8fcee53");  // 0178023P
-        //pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
-        //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1
-        //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a"); // IBA 2
-        //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");  // IBA 3
-        //pet->ScheduleLoadInstance("269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c");  // 0522c0001 TCIA
-        pet->ScheduleLoadInstance("f080888c-0ab7528a-f7d9c28c-84980eb1-ff3b0ae6");  // Captain 1
-        //pet->ScheduleLoadInstance("4f78055b-6499a2c5-1e089290-394acc05-3ec781c1");  // Captain 2
-
-        std::unique_ptr<StructureSetLoader> rtStruct(new StructureSetLoader(context_->GetWebService()));
-        //rtStruct->ScheduleLoadInstance("c2ebc17b-6b3548db-5e5da170-b8ecab71-ea03add3");  // 0178023P
-        //rtStruct->ScheduleLoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9");  // IBA
-        //rtStruct->ScheduleLoadInstance("17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20");  // 0522c0001 TCIA
-        rtStruct->ScheduleLoadInstance("96c889ab-29fe5c54-dda6e66c-3949e4da-58f90d75");  // Captain
-        
-        widget->AddLayer(new VolumeImageMPRSlicer(*ct));
-        widget->AddLayer(new VolumeImageMPRSlicer(*pet));
-        widget->AddLayer(new DicomStructureSetSlicer(*rtStruct));
-        
-        context_->AddInteractor(new Interactor(*pet, *widget, projection, 1));
-        //context_->AddInteractor(new VolumeImageInteractor(*ct, *widget, projection));
-
-        context_->AddSlicedVolume(ct.release());
-        context_->AddSlicedVolume(pet.release());
-        context_->AddVolumeLoader(rtStruct.release());
-
-        {
-          RenderStyle s;
-          //s.drawGrid_ = true;
-          s.alpha_ = 1;
-          s.windowing_ = ImageWindowing_Bone;
-          widget->SetLayerStyle(0, s);
-        }
-
-        {
-          RenderStyle s;
-          //s.drawGrid_ = true;
-          s.SetColor(255, 0, 0);  // Draw missing PET layer in red
-          s.alpha_ = 0.5;
-          s.applyLut_ = true;
-          s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
-          s.interpolation_ = ImageInterpolation_Bilinear;
-          s.windowing_ = ImageWindowing_Custom;
-          s.customWindowCenter_ = 0;
-          s.customWindowWidth_ = 128;
-          widget->SetLayerStyle(1, s);
-        }
-#endif
-
-
-        statusBar.SetMessage("Use the keys \"b\", \"l\" and \"d\" to change Hounsfield windowing");
-        statusBar.SetMessage("Use the keys \"t\" to track the (X,Y,Z) mouse coordinates");
-        statusBar.SetMessage("Use the keys \"m\" to measure distances");
-        statusBar.SetMessage("Use the keys \"c\" to draw circles");
-
-        widget->SetTransmitMouseOver(true);
-        context_->SetCentralWidget(widget.release());
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/StoneSampleCommands.yml	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#
-#        1         2         3         4         5         6         7         8
-# 345678901234567890123456789012345678901234567890123456789012345678901234567890
-#
-rootName: StoneSampleCommands
-
-# +---------------------------------+
-# | Messages from TypeScript to C++ |
-# +---------------------------------+
-
-enum Tool:
-  - LineMeasure
-  - CircleMeasure
-  - Crop
-  - Windowing
-  - Zoom
-  - Pan
-  - Move
-  - Rotate
-  - Resize
-  - Mask
-
-struct SelectTool:
-  __handler: cpp
-  tool: Tool
-
-enum ActionType:
-  - UndoCrop
-  - Rotate
-  - Invert
-
-struct Action:
-  __handler: cpp
-  type: ActionType
-
--- a/Applications/Samples/Deprecated/StoneSampleCommands_generate.py	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-import sys
-import os
-
-# add the generation script location to the search paths
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'Resources', 'CodeGeneration'))
-
-# import the code generation tooling script
-import stonegentool
-
-schemaFile = os.path.join(os.path.dirname(__file__), 'StoneSampleCommands.yml')
-outDir = os.path.dirname(__file__)
-
-# ignition!
-stonegentool.Process(schemaFile, outDir)
-
-
--- a/Applications/Samples/Deprecated/StoneSampleCommands_generated.hpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,703 +0,0 @@
-/*
-         1         2         3         4         5         6         7
-12345678901234567890123456789012345678901234567890123456789012345678901234567890
-
-Generated on 2019-03-18 12:07:42.696093 by stonegentool
-
-*/
-#pragma once
-
-#include <exception>
-#include <iostream>
-#include <string>
-#include <sstream>
-#include <assert.h>
-#include <memory>
-#include <json/json.h>
-
-//#define STONEGEN_NO_CPP11 1
-
-#ifdef STONEGEN_NO_CPP11
-#define StoneSmartPtr std::unique_ptr
-#else 
-#define StoneSmartPtr std::unique_ptr
-#endif 
-
-namespace StoneSampleCommands
-{
-  /** Throws in case of problem */
-  inline void _StoneDeserializeValue(int32_t& destValue, const Json::Value& jsonValue)
-  {
-    destValue = jsonValue.asInt();
-  }
-
-  inline Json::Value _StoneSerializeValue(int32_t value)
-  {
-    Json::Value result(value);
-    return result;
-  }
-
-  inline void _StoneDeserializeValue(Json::Value& destValue, const Json::Value& jsonValue)
-  {
-    destValue = jsonValue;
-  }
-
-  inline Json::Value _StoneSerializeValue(Json::Value value)
-  {
-    return value;
-  }
-
-  /** Throws in case of problem */
-  inline void _StoneDeserializeValue(double& destValue, const Json::Value& jsonValue)
-  {
-    destValue = jsonValue.asDouble();
-  }
-
-  inline Json::Value _StoneSerializeValue(double value)
-  {
-    Json::Value result(value);
-    return result;
-  }
-
-  /** Throws in case of problem */
-  inline void _StoneDeserializeValue(bool& destValue, const Json::Value& jsonValue)
-  {
-    destValue = jsonValue.asBool();
-  }
-
-  inline Json::Value _StoneSerializeValue(bool value)
-  {
-    Json::Value result(value);
-    return result;
-  }
-
-  /** Throws in case of problem */
-  inline void _StoneDeserializeValue(
-       std::string& destValue
-     , const Json::Value& jsonValue)
-  {
-    destValue = jsonValue.asString();
-  }
-
-  inline Json::Value _StoneSerializeValue(const std::string& value)
-  {
-    // the following is better than 
-    Json::Value result(value.data(),value.data()+value.size());
-    return result;
-  }
-
-  inline std::string MakeIndent(size_t indent)
-  {
-    char* txt = reinterpret_cast<char*>(malloc(indent+1)); // NO EXCEPTION BELOW!!!!!!!!!!!!
-    for(size_t i = 0; i < indent; ++i)
-      txt[i] = ' ';
-    txt[indent] = 0;
-    std::string retVal(txt);
-    free(txt); // NO EXCEPTION ABOVE !!!!!!!!!!
-    return retVal;
-  }
-
-  // generic dumper
-  template<typename T>
-  std::ostream& StoneDumpValue(std::ostream& out, const T& value, size_t indent)
-  {
-    out << MakeIndent(indent) << value;
-    return out;
-  }
-
-  // string dumper
-  inline std::ostream& StoneDumpValue(std::ostream& out, const std::string& value, size_t indent)
-  {
-    out << MakeIndent(indent) << "\"" << value  << "\"";
-    return out;
-  }
-
-  /** Throws in case of problem */
-  template<typename T>
-  void _StoneDeserializeValue(
-    std::map<std::string, T>& destValue, const Json::Value& jsonValue)
-  {
-    destValue.clear();
-    for (
-      Json::Value::const_iterator itr = jsonValue.begin();
-      itr != jsonValue.end();
-      itr++)
-    {
-      std::string key;
-      _StoneDeserializeValue(key, itr.key());
-
-      T innerDestValue;
-      _StoneDeserializeValue(innerDestValue, *itr);
-
-      destValue[key] = innerDestValue;
-    }
-  }
-
-  template<typename T>
-  Json::Value _StoneSerializeValue(const std::map<std::string,T>& value)
-  {
-    Json::Value result(Json::objectValue);
-
-    for (typename std::map<std::string, T>::const_iterator it = value.cbegin();
-      it != value.cend(); ++it)
-    {
-      // it->first it->second
-      result[it->first] = _StoneSerializeValue(it->second);
-    }
-    return result;
-  }
-
-  template<typename T>
-  std::ostream& StoneDumpValue(std::ostream& out, const std::map<std::string,T>& value, size_t indent)
-  {
-    out << MakeIndent(indent) << "{\n";
-    for (typename std::map<std::string, T>::const_iterator it = value.cbegin();
-      it != value.cend(); ++it)
-    {
-      out << MakeIndent(indent+2) << "\"" << it->first << "\" : ";
-      StoneDumpValue(out, it->second, indent+2);
-    }
-    out << MakeIndent(indent) << "}\n";
-    return out;
-  }
-
-  /** Throws in case of problem */
-  template<typename T>
-  void _StoneDeserializeValue(
-    std::vector<T>& destValue, const Json::Value& jsonValue)
-  {
-    destValue.clear();
-    destValue.reserve(jsonValue.size());
-    for (Json::Value::ArrayIndex i = 0; i != jsonValue.size(); i++)
-    {
-      T innerDestValue;
-      _StoneDeserializeValue(innerDestValue, jsonValue[i]);
-      destValue.push_back(innerDestValue);
-    }
-  }
-
-  template<typename T>
-  Json::Value _StoneSerializeValue(const std::vector<T>& value)
-  {
-    Json::Value result(Json::arrayValue);
-    for (size_t i = 0; i < value.size(); ++i)
-    {
-      result.append(_StoneSerializeValue(value[i]));
-    }
-    return result;
-  }
-
-  template<typename T>
-  std::ostream& StoneDumpValue(std::ostream& out, const std::vector<T>& value, size_t indent)
-  {
-    out << MakeIndent(indent) << "[\n";
-    for (size_t i = 0; i < value.size(); ++i)
-    {
-      StoneDumpValue(out, value[i], indent+2);
-    }
-    out << MakeIndent(indent) << "]\n";
-    return out;
-  }
-
-  inline void StoneCheckSerializedValueTypeGeneric(const Json::Value& value)
-  {
-    if ((!value.isMember("type")) || (!value["type"].isString()))
-    {
-      std::stringstream ss;
-      ss << "Cannot deserialize value ('type' key invalid)";
-      throw std::runtime_error(ss.str());
-    }
-  }
-
-  inline void StoneCheckSerializedValueType(
-    const Json::Value& value, std::string typeStr)
-  {
-    StoneCheckSerializedValueTypeGeneric(value);
-
-    std::string actTypeStr = value["type"].asString();
-    if (actTypeStr != typeStr)
-    {
-      std::stringstream ss;
-      ss << "Cannot deserialize type" << actTypeStr
-        << "into " << typeStr;
-      throw std::runtime_error(ss.str());
-    }
-  }
-
-  // end of generic methods
-
-// end of generic methods
-
-  enum Tool {
-    Tool_LineMeasure,
-    Tool_CircleMeasure,
-    Tool_Crop,
-    Tool_Windowing,
-    Tool_Zoom,
-    Tool_Pan,
-    Tool_Move,
-    Tool_Rotate,
-    Tool_Resize,
-    Tool_Mask,
-  };
-
-  inline std::string ToString(const Tool& value)
-  {
-    if( value == Tool_LineMeasure)
-    {
-      return std::string("LineMeasure");
-    }
-    if( value == Tool_CircleMeasure)
-    {
-      return std::string("CircleMeasure");
-    }
-    if( value == Tool_Crop)
-    {
-      return std::string("Crop");
-    }
-    if( value == Tool_Windowing)
-    {
-      return std::string("Windowing");
-    }
-    if( value == Tool_Zoom)
-    {
-      return std::string("Zoom");
-    }
-    if( value == Tool_Pan)
-    {
-      return std::string("Pan");
-    }
-    if( value == Tool_Move)
-    {
-      return std::string("Move");
-    }
-    if( value == Tool_Rotate)
-    {
-      return std::string("Rotate");
-    }
-    if( value == Tool_Resize)
-    {
-      return std::string("Resize");
-    }
-    if( value == Tool_Mask)
-    {
-      return std::string("Mask");
-    }
-    std::stringstream ss;
-    ss << "Value \"" << value << "\" cannot be converted to Tool. Possible values are: "
-        << " LineMeasure = " << static_cast<int64_t>(Tool_LineMeasure)  << ", " 
-        << " CircleMeasure = " << static_cast<int64_t>(Tool_CircleMeasure)  << ", " 
-        << " Crop = " << static_cast<int64_t>(Tool_Crop)  << ", " 
-        << " Windowing = " << static_cast<int64_t>(Tool_Windowing)  << ", " 
-        << " Zoom = " << static_cast<int64_t>(Tool_Zoom)  << ", " 
-        << " Pan = " << static_cast<int64_t>(Tool_Pan)  << ", " 
-        << " Move = " << static_cast<int64_t>(Tool_Move)  << ", " 
-        << " Rotate = " << static_cast<int64_t>(Tool_Rotate)  << ", " 
-        << " Resize = " << static_cast<int64_t>(Tool_Resize)  << ", " 
-        << " Mask = " << static_cast<int64_t>(Tool_Mask)  << ", " 
-        << std::endl;
-    std::string msg = ss.str();
-    throw std::runtime_error(msg);
-  }
-
-  inline void FromString(Tool& value, std::string strValue)
-  {
-    if( strValue == std::string("LineMeasure") )
-    {
-      value = Tool_LineMeasure;
-      return;
-    }
-    if( strValue == std::string("CircleMeasure") )
-    {
-      value = Tool_CircleMeasure;
-      return;
-    }
-    if( strValue == std::string("Crop") )
-    {
-      value = Tool_Crop;
-      return;
-    }
-    if( strValue == std::string("Windowing") )
-    {
-      value = Tool_Windowing;
-      return;
-    }
-    if( strValue == std::string("Zoom") )
-    {
-      value = Tool_Zoom;
-      return;
-    }
-    if( strValue == std::string("Pan") )
-    {
-      value = Tool_Pan;
-      return;
-    }
-    if( strValue == std::string("Move") )
-    {
-      value = Tool_Move;
-      return;
-    }
-    if( strValue == std::string("Rotate") )
-    {
-      value = Tool_Rotate;
-      return;
-    }
-    if( strValue == std::string("Resize") )
-    {
-      value = Tool_Resize;
-      return;
-    }
-    if( strValue == std::string("Mask") )
-    {
-      value = Tool_Mask;
-      return;
-    }
-
-    std::stringstream ss;
-    ss << "String \"" << strValue << "\" cannot be converted to Tool. Possible values are: LineMeasure CircleMeasure Crop Windowing Zoom Pan Move Rotate Resize Mask ";
-    std::string msg = ss.str();
-    throw std::runtime_error(msg);
-  }
-
-
-  inline void _StoneDeserializeValue(
-    Tool& destValue, const Json::Value& jsonValue)
-  {
-    FromString(destValue, jsonValue.asString());
-  }
-
-  inline Json::Value _StoneSerializeValue(const Tool& value)
-  {
-    std::string strValue = ToString(value);
-    return Json::Value(strValue);
-  }
-
-  inline std::ostream& StoneDumpValue(std::ostream& out, const Tool& value, size_t indent = 0)
-  {
-    if( value == Tool_LineMeasure)
-    {
-      out << MakeIndent(indent) << "LineMeasure" << std::endl;
-    }
-    if( value == Tool_CircleMeasure)
-    {
-      out << MakeIndent(indent) << "CircleMeasure" << std::endl;
-    }
-    if( value == Tool_Crop)
-    {
-      out << MakeIndent(indent) << "Crop" << std::endl;
-    }
-    if( value == Tool_Windowing)
-    {
-      out << MakeIndent(indent) << "Windowing" << std::endl;
-    }
-    if( value == Tool_Zoom)
-    {
-      out << MakeIndent(indent) << "Zoom" << std::endl;
-    }
-    if( value == Tool_Pan)
-    {
-      out << MakeIndent(indent) << "Pan" << std::endl;
-    }
-    if( value == Tool_Move)
-    {
-      out << MakeIndent(indent) << "Move" << std::endl;
-    }
-    if( value == Tool_Rotate)
-    {
-      out << MakeIndent(indent) << "Rotate" << std::endl;
-    }
-    if( value == Tool_Resize)
-    {
-      out << MakeIndent(indent) << "Resize" << std::endl;
-    }
-    if( value == Tool_Mask)
-    {
-      out << MakeIndent(indent) << "Mask" << std::endl;
-    }
-    return out;
-  }
-
-
-  enum ActionType {
-    ActionType_UndoCrop,
-    ActionType_Rotate,
-    ActionType_Invert,
-  };
-
-  inline std::string ToString(const ActionType& value)
-  {
-    if( value == ActionType_UndoCrop)
-    {
-      return std::string("UndoCrop");
-    }
-    if( value == ActionType_Rotate)
-    {
-      return std::string("Rotate");
-    }
-    if( value == ActionType_Invert)
-    {
-      return std::string("Invert");
-    }
-    std::stringstream ss;
-    ss << "Value \"" << value << "\" cannot be converted to ActionType. Possible values are: "
-        << " UndoCrop = " << static_cast<int64_t>(ActionType_UndoCrop)  << ", " 
-        << " Rotate = " << static_cast<int64_t>(ActionType_Rotate)  << ", " 
-        << " Invert = " << static_cast<int64_t>(ActionType_Invert)  << ", " 
-        << std::endl;
-    std::string msg = ss.str();
-    throw std::runtime_error(msg);
-  }
-
-  inline void FromString(ActionType& value, std::string strValue)
-  {
-    if( strValue == std::string("UndoCrop") )
-    {
-      value = ActionType_UndoCrop;
-      return;
-    }
-    if( strValue == std::string("Rotate") )
-    {
-      value = ActionType_Rotate;
-      return;
-    }
-    if( strValue == std::string("Invert") )
-    {
-      value = ActionType_Invert;
-      return;
-    }
-
-    std::stringstream ss;
-    ss << "String \"" << strValue << "\" cannot be converted to ActionType. Possible values are: UndoCrop Rotate Invert ";
-    std::string msg = ss.str();
-    throw std::runtime_error(msg);
-  }
-
-
-  inline void _StoneDeserializeValue(
-    ActionType& destValue, const Json::Value& jsonValue)
-  {
-    FromString(destValue, jsonValue.asString());
-  }
-
-  inline Json::Value _StoneSerializeValue(const ActionType& value)
-  {
-    std::string strValue = ToString(value);
-    return Json::Value(strValue);
-  }
-
-  inline std::ostream& StoneDumpValue(std::ostream& out, const ActionType& value, size_t indent = 0)
-  {
-    if( value == ActionType_UndoCrop)
-    {
-      out << MakeIndent(indent) << "UndoCrop" << std::endl;
-    }
-    if( value == ActionType_Rotate)
-    {
-      out << MakeIndent(indent) << "Rotate" << std::endl;
-    }
-    if( value == ActionType_Invert)
-    {
-      out << MakeIndent(indent) << "Invert" << std::endl;
-    }
-    return out;
-  }
-
-
-
-#ifdef _MSC_VER
-#pragma region SelectTool
-#endif //_MSC_VER
-
-  struct SelectTool
-  {
-    Tool tool;
-
-    SelectTool(Tool tool = Tool())
-    {
-      this->tool = tool;
-    }
-  };
-
-  inline void _StoneDeserializeValue(SelectTool& destValue, const Json::Value& value)
-  {
-    _StoneDeserializeValue(destValue.tool, value["tool"]);
-    }
-
-  inline Json::Value _StoneSerializeValue(const SelectTool& value)
-  {
-    Json::Value result(Json::objectValue);
-    result["tool"] = _StoneSerializeValue(value.tool);
-
-    return result;
-  }
-
-  inline std::ostream& StoneDumpValue(std::ostream& out, const SelectTool& value, size_t indent = 0)
-  {
-    out << MakeIndent(indent) << "{\n";
-    out << MakeIndent(indent) << "tool:\n";
-    StoneDumpValue(out, value.tool,indent+2);
-    out << "\n";
-
-    out << MakeIndent(indent) << "}\n";
-    return out;
-  }
-
-  inline void StoneDeserialize(SelectTool& destValue, const Json::Value& value)
-  {
-    StoneCheckSerializedValueType(value, "StoneSampleCommands.SelectTool");
-    _StoneDeserializeValue(destValue, value["value"]);
-  }
-
-  inline Json::Value StoneSerializeToJson(const SelectTool& value)
-  {
-    Json::Value result(Json::objectValue);
-    result["type"] = "StoneSampleCommands.SelectTool";
-    result["value"] = _StoneSerializeValue(value);
-    return result;
-  }
-
-  inline std::string StoneSerialize(const SelectTool& value)
-  {
-    Json::Value resultJson = StoneSerializeToJson(value);
-    std::string resultStr = resultJson.toStyledString();
-    return resultStr;
-  }
-
-#ifdef _MSC_VER
-#pragma endregion SelectTool
-#endif //_MSC_VER
-
-#ifdef _MSC_VER
-#pragma region Action
-#endif //_MSC_VER
-
-  struct Action
-  {
-    ActionType type;
-
-    Action(ActionType type = ActionType())
-    {
-      this->type = type;
-    }
-  };
-
-  inline void _StoneDeserializeValue(Action& destValue, const Json::Value& value)
-  {
-    _StoneDeserializeValue(destValue.type, value["type"]);
-    }
-
-  inline Json::Value _StoneSerializeValue(const Action& value)
-  {
-    Json::Value result(Json::objectValue);
-    result["type"] = _StoneSerializeValue(value.type);
-
-    return result;
-  }
-
-  inline std::ostream& StoneDumpValue(std::ostream& out, const Action& value, size_t indent = 0)
-  {
-    out << MakeIndent(indent) << "{\n";
-    out << MakeIndent(indent) << "type:\n";
-    StoneDumpValue(out, value.type,indent+2);
-    out << "\n";
-
-    out << MakeIndent(indent) << "}\n";
-    return out;
-  }
-
-  inline void StoneDeserialize(Action& destValue, const Json::Value& value)
-  {
-    StoneCheckSerializedValueType(value, "StoneSampleCommands.Action");
-    _StoneDeserializeValue(destValue, value["value"]);
-  }
-
-  inline Json::Value StoneSerializeToJson(const Action& value)
-  {
-    Json::Value result(Json::objectValue);
-    result["type"] = "StoneSampleCommands.Action";
-    result["value"] = _StoneSerializeValue(value);
-    return result;
-  }
-
-  inline std::string StoneSerialize(const Action& value)
-  {
-    Json::Value resultJson = StoneSerializeToJson(value);
-    std::string resultStr = resultJson.toStyledString();
-    return resultStr;
-  }
-
-#ifdef _MSC_VER
-#pragma endregion Action
-#endif //_MSC_VER
-
-#ifdef _MSC_VER
-#pragma region Dispatching code
-#endif //_MSC_VER
-
-  class IHandler
-  {
-  public:
-    virtual bool Handle(const SelectTool& value) = 0;
-    virtual bool Handle(const Action& value) = 0;
-  };
-
-  /** Service function for StoneDispatchToHandler */
-  inline bool StoneDispatchJsonToHandler(
-    const Json::Value& jsonValue, IHandler* handler)
-  {
-    StoneCheckSerializedValueTypeGeneric(jsonValue);
-    std::string type = jsonValue["type"].asString();
-    if (type == "")
-    {
-      // this should never ever happen
-      throw std::runtime_error("Caught empty type while dispatching");
-    }
-    else if (type == "StoneSampleCommands.SelectTool")
-    {
-      SelectTool value;
-      _StoneDeserializeValue(value, jsonValue["value"]);
-      return handler->Handle(value);
-    }
-    else if (type == "StoneSampleCommands.Action")
-    {
-      Action value;
-      _StoneDeserializeValue(value, jsonValue["value"]);
-      return handler->Handle(value);
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-  /** Takes a serialized type and passes this to the handler */
-  inline bool StoneDispatchToHandler(std::string strValue, IHandler* handler)
-  {
-    Json::Value readValue;
-
-    Json::CharReaderBuilder builder;
-    Json::CharReader* reader = builder.newCharReader();
-
-    StoneSmartPtr<Json::CharReader> ptr(reader);
-
-    std::string errors;
-
-    bool ok = reader->parse(
-      strValue.c_str(),
-      strValue.c_str() + strValue.size(),
-      &readValue,
-      &errors
-    );
-    if (!ok)
-    {
-      std::stringstream ss;
-      ss << "Jsoncpp parsing error: " << errors;
-      throw std::runtime_error(ss.str());
-    }
-    return StoneDispatchJsonToHandler(readValue, handler);
-  }
-
-#ifdef _MSC_VER
-#pragma endregion Dispatching code
-#endif //_MSC_VER
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/StoneSampleCommands_generated.ts	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@
-/*
-         1         2         3         4         5         6         7
-12345678901234567890123456789012345678901234567890123456789012345678901234567890
-
-Generated on 2019-03-18 12:07:42.696093 by stonegentool
-
-*/
-
-function StoneCheckSerializedValueType(value: any, typeStr: string)
-{
-  StoneCheckSerializedValueTypeGeneric(value);
-
-  if (value['type'] != typeStr)
-  {
-    throw new Error(
-      `Cannot deserialize type ${value['type']} into ${typeStr}`);
-  }
-}
-
-function isString(val: any) :boolean
-{
-  return ((typeof val === 'string') || (val instanceof String));
-}
-
-function StoneCheckSerializedValueTypeGeneric(value: any)
-{
-  // console.//log("+-------------------------------------------------+");
-  // console.//log("|            StoneCheckSerializedValueTypeGeneric |");
-  // console.//log("+-------------------------------------------------+");
-  // console.//log("value = ");
-  // console.//log(value);
-  if ( (!('type' in value)) || (!isString(value.type)) )
-  {
-    throw new Error(
-      "Cannot deserialize value ('type' key invalid)");
-  }
-}
-
-// end of generic methods
-
-export enum Tool {
-  LineMeasure = "LineMeasure",
-  CircleMeasure = "CircleMeasure",
-  Crop = "Crop",
-  Windowing = "Windowing",
-  Zoom = "Zoom",
-  Pan = "Pan",
-  Move = "Move",
-  Rotate = "Rotate",
-  Resize = "Resize",
-  Mask = "Mask"
-};
-
-export function Tool_FromString(strValue:string) : Tool
-{
-  if( strValue == "LineMeasure" )
-  {
-    return Tool.LineMeasure;
-  }
-  if( strValue == "CircleMeasure" )
-  {
-    return Tool.CircleMeasure;
-  }
-  if( strValue == "Crop" )
-  {
-    return Tool.Crop;
-  }
-  if( strValue == "Windowing" )
-  {
-    return Tool.Windowing;
-  }
-  if( strValue == "Zoom" )
-  {
-    return Tool.Zoom;
-  }
-  if( strValue == "Pan" )
-  {
-    return Tool.Pan;
-  }
-  if( strValue == "Move" )
-  {
-    return Tool.Move;
-  }
-  if( strValue == "Rotate" )
-  {
-    return Tool.Rotate;
-  }
-  if( strValue == "Resize" )
-  {
-    return Tool.Resize;
-  }
-  if( strValue == "Mask" )
-  {
-    return Tool.Mask;
-  }
-
-  let msg : string =  `String ${strValue} cannot be converted to Tool. Possible values are: LineMeasure, CircleMeasure, Crop, Windowing, Zoom, Pan, Move, Rotate, Resize, Mask`;
-  throw new Error(msg);
-}
-
-export function Tool_ToString(value:Tool) : string
-{
-  if( value == Tool.LineMeasure )
-  {
-    return "LineMeasure";
-  }
-  if( value == Tool.CircleMeasure )
-  {
-    return "CircleMeasure";
-  }
-  if( value == Tool.Crop )
-  {
-    return "Crop";
-  }
-  if( value == Tool.Windowing )
-  {
-    return "Windowing";
-  }
-  if( value == Tool.Zoom )
-  {
-    return "Zoom";
-  }
-  if( value == Tool.Pan )
-  {
-    return "Pan";
-  }
-  if( value == Tool.Move )
-  {
-    return "Move";
-  }
-  if( value == Tool.Rotate )
-  {
-    return "Rotate";
-  }
-  if( value == Tool.Resize )
-  {
-    return "Resize";
-  }
-  if( value == Tool.Mask )
-  {
-    return "Mask";
-  }
-
-  let msg : string = `Value ${value} cannot be converted to Tool. Possible values are: `;
-  {
-    let _LineMeasure_enumValue : string = Tool.LineMeasure; // enums are strings in stonecodegen, so this will work.
-    let msg_LineMeasure : string = `LineMeasure (${_LineMeasure_enumValue}), `;
-    msg = msg + msg_LineMeasure;
-  }
-  {
-    let _CircleMeasure_enumValue : string = Tool.CircleMeasure; // enums are strings in stonecodegen, so this will work.
-    let msg_CircleMeasure : string = `CircleMeasure (${_CircleMeasure_enumValue}), `;
-    msg = msg + msg_CircleMeasure;
-  }
-  {
-    let _Crop_enumValue : string = Tool.Crop; // enums are strings in stonecodegen, so this will work.
-    let msg_Crop : string = `Crop (${_Crop_enumValue}), `;
-    msg = msg + msg_Crop;
-  }
-  {
-    let _Windowing_enumValue : string = Tool.Windowing; // enums are strings in stonecodegen, so this will work.
-    let msg_Windowing : string = `Windowing (${_Windowing_enumValue}), `;
-    msg = msg + msg_Windowing;
-  }
-  {
-    let _Zoom_enumValue : string = Tool.Zoom; // enums are strings in stonecodegen, so this will work.
-    let msg_Zoom : string = `Zoom (${_Zoom_enumValue}), `;
-    msg = msg + msg_Zoom;
-  }
-  {
-    let _Pan_enumValue : string = Tool.Pan; // enums are strings in stonecodegen, so this will work.
-    let msg_Pan : string = `Pan (${_Pan_enumValue}), `;
-    msg = msg + msg_Pan;
-  }
-  {
-    let _Move_enumValue : string = Tool.Move; // enums are strings in stonecodegen, so this will work.
-    let msg_Move : string = `Move (${_Move_enumValue}), `;
-    msg = msg + msg_Move;
-  }
-  {
-    let _Rotate_enumValue : string = Tool.Rotate; // enums are strings in stonecodegen, so this will work.
-    let msg_Rotate : string = `Rotate (${_Rotate_enumValue}), `;
-    msg = msg + msg_Rotate;
-  }
-  {
-    let _Resize_enumValue : string = Tool.Resize; // enums are strings in stonecodegen, so this will work.
-    let msg_Resize : string = `Resize (${_Resize_enumValue}), `;
-    msg = msg + msg_Resize;
-  }
-  {
-    let _Mask_enumValue : string = Tool.Mask; // enums are strings in stonecodegen, so this will work.
-    let msg_Mask : string = `Mask (${_Mask_enumValue})`;
-    msg = msg + msg_Mask;
-  }
-  throw new Error(msg);
-}
-
-export enum ActionType {
-  UndoCrop = "UndoCrop",
-  Rotate = "Rotate",
-  Invert = "Invert"
-};
-
-export function ActionType_FromString(strValue:string) : ActionType
-{
-  if( strValue == "UndoCrop" )
-  {
-    return ActionType.UndoCrop;
-  }
-  if( strValue == "Rotate" )
-  {
-    return ActionType.Rotate;
-  }
-  if( strValue == "Invert" )
-  {
-    return ActionType.Invert;
-  }
-
-  let msg : string =  `String ${strValue} cannot be converted to ActionType. Possible values are: UndoCrop, Rotate, Invert`;
-  throw new Error(msg);
-}
-
-export function ActionType_ToString(value:ActionType) : string
-{
-  if( value == ActionType.UndoCrop )
-  {
-    return "UndoCrop";
-  }
-  if( value == ActionType.Rotate )
-  {
-    return "Rotate";
-  }
-  if( value == ActionType.Invert )
-  {
-    return "Invert";
-  }
-
-  let msg : string = `Value ${value} cannot be converted to ActionType. Possible values are: `;
-  {
-    let _UndoCrop_enumValue : string = ActionType.UndoCrop; // enums are strings in stonecodegen, so this will work.
-    let msg_UndoCrop : string = `UndoCrop (${_UndoCrop_enumValue}), `;
-    msg = msg + msg_UndoCrop;
-  }
-  {
-    let _Rotate_enumValue : string = ActionType.Rotate; // enums are strings in stonecodegen, so this will work.
-    let msg_Rotate : string = `Rotate (${_Rotate_enumValue}), `;
-    msg = msg + msg_Rotate;
-  }
-  {
-    let _Invert_enumValue : string = ActionType.Invert; // enums are strings in stonecodegen, so this will work.
-    let msg_Invert : string = `Invert (${_Invert_enumValue})`;
-    msg = msg + msg_Invert;
-  }
-  throw new Error(msg);
-}
-
-
-
-export class SelectTool {
-  tool:Tool;
-
-  constructor() {
-  }
-
-  public StoneSerialize(): string {
-    let container: object = {};
-    container['type'] = 'StoneSampleCommands.SelectTool';
-    container['value'] = this;
-    return JSON.stringify(container);
-  }
-
-  public static StoneDeserialize(valueStr: string) : SelectTool
-  {
-    let value: any = JSON.parse(valueStr);
-    StoneCheckSerializedValueType(value, 'StoneSampleCommands.SelectTool');
-    let result: SelectTool = value['value'] as SelectTool;
-    return result;
-  }
-}
-export class Action {
-  type:ActionType;
-
-  constructor() {
-  }
-
-  public StoneSerialize(): string {
-    let container: object = {};
-    container['type'] = 'StoneSampleCommands.Action';
-    container['value'] = this;
-    return JSON.stringify(container);
-  }
-
-  public static StoneDeserialize(valueStr: string) : Action
-  {
-    let value: any = JSON.parse(valueStr);
-    StoneCheckSerializedValueType(value, 'StoneSampleCommands.Action');
-    let result: Action = value['value'] as Action;
-    return result;
-  }
-}
-
-export interface IHandler {
-};
-
-/** Service function for StoneDispatchToHandler */
-export function StoneDispatchJsonToHandler(
-  jsonValue: any, handler: IHandler): boolean
-{
-  StoneCheckSerializedValueTypeGeneric(jsonValue);
-  let type: string = jsonValue["type"];
-  if (type == "")
-  {
-    // this should never ever happen
-    throw new Error("Caught empty type while dispatching");
-  }
-  else
-  {
-    return false;
-  }
-}
-
-/** Takes a serialized type and passes this to the handler */
-export function StoneDispatchToHandler(
-  strValue: string, handler: IHandler): boolean
-{
-  // console.//log("+------------------------------------------------+");
-  // console.//log("|            StoneDispatchToHandler              |");
-  // console.//log("+------------------------------------------------+");
-  // console.//log("strValue = ");
-  // console.//log(strValue);
-  let jsonValue: any = JSON.parse(strValue)
-  return StoneDispatchJsonToHandler(jsonValue, handler);
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/SynchronizedSeriesApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleInteractor.h"
-
-#include "../../../Framework/Toolbox/OrthancSeriesLoader.h"
-#include "../../../Framework/Layers/SeriesFrameRendererFactory.h"
-#include "../../../Framework/Layers/ReferenceLineFactory.h"
-#include "../../../Framework/Widgets/LayoutWidget.h"
-
-#include <Core/Logging.h>
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class SynchronizedSeriesApplication : public SampleApplicationBase
-    {
-    private:   
-      LayeredSceneWidget* CreateSeriesWidget(BasicApplicationContext& context,
-                                             const std::string& series)
-      {
-        std::unique_ptr<ISeriesLoader> loader
-          (new OrthancSeriesLoader(context.GetWebService().GetConnection(), series));
-
-        std::unique_ptr<SampleInteractor> interactor(new SampleInteractor(*loader, false));
-
-        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
-        widget->AddLayer(new SeriesFrameRendererFactory(loader.release(), false));
-        widget->SetSlice(interactor->GetCursor().GetCurrentSlice());
-        widget->SetInteractor(*interactor);
-
-        context.AddInteractor(interactor.release());
-
-        return widget.release();
-      }
-
-    public:
-      virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("a", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the 1st series")
-          ("b", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the 2nd series")
-          ("c", boost::program_options::value<std::string>(), 
-           "Orthanc ID of the 3rd series")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(BasicApplicationContext& context,
-                              IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        if (parameters.count("a") != 1 ||
-            parameters.count("b") != 1 ||
-            parameters.count("c") != 1)
-        {
-          LOG(ERROR) << "At least one of the three series IDs is missing";
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-        }
-
-        std::unique_ptr<LayeredSceneWidget> a(CreateSeriesWidget(context, parameters["a"].as<std::string>()));
-        std::unique_ptr<LayeredSceneWidget> b(CreateSeriesWidget(context, parameters["b"].as<std::string>()));
-        std::unique_ptr<LayeredSceneWidget> c(CreateSeriesWidget(context, parameters["c"].as<std::string>()));
-
-        ReferenceLineFactory::Configure(*a, *b);
-        ReferenceLineFactory::Configure(*a, *c);
-        ReferenceLineFactory::Configure(*b, *c);
-
-        std::unique_ptr<LayoutWidget> layout(new LayoutWidget);
-        layout->SetPadding(5);
-        layout->AddWidget(a.release());
-
-        std::unique_ptr<LayoutWidget> layoutB(new LayoutWidget);
-        layoutB->SetVertical();
-        layoutB->SetPadding(5);
-        layoutB->AddWidget(b.release());
-        layoutB->AddWidget(c.release());
-        layout->AddWidget(layoutB.release());
-
-        context.SetCentralWidget(layout.release());        
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/TestPatternApplication.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "SampleApplicationBase.h"
-
-#include "../../../Framework/Widgets/TestCairoWidget.h"
-#include "../../../Framework/Widgets/TestWorldSceneWidget.h"
-#include "../../../Framework/Widgets/LayoutWidget.h"
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class TestPatternApplication : public SampleApplicationBase
-    {
-    public:
-      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic("Sample options");
-        generic.add_options()
-          ("animate", boost::program_options::value<bool>()->default_value(true), "Animate the test pattern")
-          ;
-
-        options.add(generic);    
-      }
-
-      virtual void Initialize(IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters)
-      {
-        using namespace OrthancStone;
-
-        std::unique_ptr<LayoutWidget> layout(new LayoutWidget);
-        layout->SetPadding(10);
-        layout->SetBackgroundCleared(true);
-        layout->AddWidget(new TestCairoWidget(parameters["animate"].as<bool>()));
-        layout->AddWidget(new TestWorldSceneWidget(parameters["animate"].as<bool>()));
-
-        context_->SetCentralWidget(layout.release());
-        context_->SetUpdateDelay(25);  // If animation, update the content each 25ms
-      }
-    };
-  }
-}
--- a/Applications/Samples/Deprecated/Web/index.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <!-- Disable pinch zoom on mobile devices -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta name="HandheldFriendly" content="true" />
-
-    <title>Wasm Samples</title>
-
-<body>
-    <ul>
-      <li><a href="simple-viewer/simple-viewer.html">Simple Viewer Project (you may add ?studyId=XXX in the url)</a></li>
-      <li><a href="single-frame.html?instance=XXX">Single frame application (you must replace XXX by a valid instance id in the url)</a></li>
-      <li><a href="single-frame-editor.html?instance=XXX">Single frame editor application (you must replace XXX by a valid instance id in the url)</a></li>
-      <li><a href="simple-viewer-single-file.html">Simple Viewer Single file (to be replaced by other samples)</a></li>
-    </ul>
-</body>
-
-</html>
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Web/samples-styles.css	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-html, body {
-  width: 100%;
-  height: 100%;
-  margin: 0px;
-  border: 0;
-  overflow: hidden; /*  Disable scrollbars */
-  display: block;  /* No floating content on sides */
-  background-color: black;
-  color: white;
-  font-family: Arial, Helvetica, sans-serif;
-}
-
-canvas {
-  left:0px;
-  top:0px;
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Web/simple-viewer-single-file.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-
-<head>
-  <meta charset="utf-8" />
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-  <!-- Disable pinch zoom on mobile devices -->
-  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-  <meta name="HandheldFriendly" content="true" />
-
-  <title>Simple Viewer</title>
-  <link href="samples-styles.css" rel="stylesheet" />
-
-<body>
-  <div id="breadcrumb">
-    <span id="patient-id"></span>
-    <span id="study-description"></span>
-    <span id="series-description"></span>
-  </div>
-  <div style="height: calc(100% - 50px)">
-    <div style="width: 20%; height: 100%; display: inline-block">
-      <canvas id="canvas"></canvas>
-    </div>
-    <div style="width: 70%; height: 100%; display: inline-block">
-      <canvas id="canvas2"></canvas>
-    </div>
-  </div>
-  <div id="toolbox" style="height: 50px">
-    <input tool-selector="line-measure" type="radio" name="radio-tool-selector" class="tool-selector">line
-    <input tool-selector="circle-measure" type="radio" name="radio-tool-selector" class="tool-selector">circle
-    <button action-trigger="action1" class="action-trigger">action1</button>
-    <button action-trigger="action2" class="action-trigger">action2</button>
-  </div>
-  <script type="text/javascript" src="app-simple-viewer-single-file.js"></script>
-</body>
-
-</html>
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Web/simple-viewer-single-file.ts	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-import wasmApplicationRunner = require('../../../Platforms/Wasm/wasm-application-runner');
-
-wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSimpleViewerSingleFile", "/orthanc");
-
-function SelectTool(toolName: string) {
-    var command = {
-        command: "selectTool",
-        args: {
-            toolName: toolName
-        }
-    };
-    wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
-
-}
-
-function PerformAction(commandName: string) {
-    var command = {
-        command: commandName,
-        commandType: "simple",
-        args: {}
-    };
-    wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
-}
-
-//initializes the buttons
-//-----------------------
-// install "SelectTool" handlers
-document.querySelectorAll("[tool-selector]").forEach((e) => {
-    console.log(e);
-    (e as HTMLInputElement).addEventListener("click", () => {
-        console.log(e);
-        SelectTool(e.attributes["tool-selector"].value);
-    });
-});
-
-// install "PerformAction" handlers
-document.querySelectorAll("[action-trigger]").forEach((e) => {
-    (e as HTMLInputElement).addEventListener("click", () => {
-        PerformAction(e.attributes["action-trigger"].value);
-    });
-});
-
-// this method is called "from the C++ code" when the StoneApplication is updated.
-// it can be used to update the UI of the application
-function UpdateWebApplicationWithString(statusUpdateMessage: string) {
-  console.log(statusUpdateMessage);
-  
-  if (statusUpdateMessage.startsWith("series-description=")) {
-      document.getElementById("series-description").innerText = statusUpdateMessage.split("=")[1];
-  }
-}
-
-function UpdateWebApplicationWithSerializedMessage(statusUpdateMessageString: string) {
-  console.log("updating web application with serialized message: ", statusUpdateMessageString);
-  console.log("<not supported in the simple viewer (single file)!>");
-}
-
-// make it available to other js scripts in the application
-(<any> window).UpdateWebApplicationWithString = UpdateWebApplicationWithString;
-
-(<any> window).UpdateWebApplicationWithSerializedMessage = UpdateWebApplicationWithSerializedMessage;
--- a/Applications/Samples/Deprecated/Web/simple-viewer-single-file.tsconfig.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-{
-    "extends" : "./tsconfig-samples",
-    "compilerOptions": {
-        // "outFile": "../build-web/app-simple-viewer-single-file.js"
-    },
-    "include" : [
-        "simple-viewer-single-file.ts"
-    ]
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Web/single-frame-editor.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <!-- Disable pinch zoom on mobile devices -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta name="HandheldFriendly" content="true" />
-
-    <title>Simple Viewer</title>
-    <link href="samples-styles.css" rel="stylesheet" />
-
-<body>
-  <div style="width: 100%; height: 100%">
-    <canvas id="canvas"></canvas>
-  </div>
-  <script type="text/javascript" src="app-single-frame-editor.js"></script>
-</body>
-
-</html>
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Web/single-frame-editor.ts	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-import wasmApplicationRunner = require('../../../Platforms/Wasm/wasm-application-runner');
-
-wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSingleFrameEditor", "/orthanc");
--- a/Applications/Samples/Deprecated/Web/single-frame-editor.tsconfig.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-{
-    "extends" : "./tsconfig-samples",
-    "compilerOptions": {
-    },
-    "include" : [
-        "single-frame-editor.ts"
-    ]
-}
--- a/Applications/Samples/Deprecated/Web/single-frame.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <!-- Disable pinch zoom on mobile devices -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta name="HandheldFriendly" content="true" />
-
-    <title>Simple Viewer</title>
-    <link href="samples-styles.css" rel="stylesheet" />
-
-<body>
-  <div style="width: 100%; height: 100%">
-    <canvas id="canvas"></canvas>
-  </div>
-  <script type="text/javascript" src="app-single-frame.js"></script>
-</body>
-
-</html>
\ No newline at end of file
--- a/Applications/Samples/Deprecated/Web/single-frame.ts	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-import wasmApplicationRunner = require('../../../Platforms/Wasm/wasm-application-runner');
-
-wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSingleFrame", "/orthanc");
-
--- a/Applications/Samples/Deprecated/Web/single-frame.tsconfig.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-{
-    "extends" : "./tsconfig-samples",
-    "compilerOptions": {
-    },
-    "include" : [
-        "single-frame.ts"
-    ]
-}
--- a/Applications/Samples/Deprecated/Web/tsconfig-samples.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-{
-    "extends" : "../../../Platforms/Wasm/tsconfig-stone",
-    "compilerOptions": {
-        "sourceMap": false,
-        "lib" : [
-            "es2017",
-            "dom",
-            "dom.iterable"
-        ]
-    }
-}
--- a/Applications/Samples/Deprecated/build-wasm.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#!/bin/bash
-#
-# usage:
-# to build all targets in Debug:
-# ./build-wasm.sh
-#
-# to build a single target in release:
-# ./build-wasm.sh OrthancStoneSingleFrameEditor Release
-
-set -e
-
-target=${1:-all}
-buildType=${2:-Debug}
-
-currentDir=$(pwd)
-samplesRootDir=$(pwd)
-
-mkdir -p $samplesRootDir/build-wasm
-cd $samplesRootDir/build-wasm
-
-source ~/apps/emsdk/emsdk_env.sh
-cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=~/apps/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=$buildType -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
-ninja $target
-
-echo "-- building the web application -- "
-cd $currentDir
-./build-web.sh
\ No newline at end of file
--- a/Applications/Samples/Deprecated/build-wasm.sh.old	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# usage:
-# to build all targets:
-# ./build-wasm.sh
-#
-# to build a single target:
-# ./build-wasm.sh OrthancStoneSingleFrameEditor
-
-set -e
-
-target=${1:-all}
-
-currentDir=$(pwd)
-samplesRootDir=$(pwd)
-
-mkdir -p $samplesRootDir/build-wasm
-cd $samplesRootDir/build-wasm
-
-source ~/apps/emsdk/emsdk_env.sh
-cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake \
-  -DCMAKE_BUILD_TYPE=Release \
-  -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone \
-  -DORTHANC_FRAMEWORK_SOURCE=path \
-  -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc \
-  -DALLOW_DOWNLOADS=ON .. \
-  -DENABLE_WASM=ON
-
-ninja $target
-
-echo "-- building the web application -- "
-cd $currentDir
-./build-web.sh
--- a/Applications/Samples/Deprecated/build-web-ext.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-#!/bin/bash
-
-set -e
-
-target=${1:-all}
-# this script currently assumes that the wasm code has been built on its side and is availabie in build-wasm/
-
-currentDir=$(pwd)
-
-scriptDirRel=$(dirname $0)
-#echo $scriptDirRel
-scriptDirAbs=$(realpath $scriptDirRel)
-echo $scriptDirAbs
-
-samplesRootDir=scriptDirAbs
-
-outputDir=$samplesRootDir/build-web/
-mkdir -p $outputDir
-
-# files used by all single files samples
-cp $samplesRootDir/Web/index.html $outputDir
-cp $samplesRootDir/Web/samples-styles.css $outputDir
-
-# build simple-viewer-single-file (obsolete project)
-if [[ $target == "all" || $target == "OrthancStoneSimpleViewerSingleFile" ]]; then
-  cp $samplesRootDir/Web/simple-viewer-single-file.html $outputDir
-  tsc --allowJs --project $samplesRootDir/Web/simple-viewer-single-file.tsconfig.json
-  cp $currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.js  $outputDir
-  cp $currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.wasm  $outputDir
-fi
-
-# build single-frame
-if [[ $target == "all" || $target == "OrthancStoneSingleFrame" ]]; then
-  cp $samplesRootDir/Web/single-frame.html $outputDir
-  tsc --allowJs --project $samplesRootDir/Web/single-frame.tsconfig.json
-  cp $currentDir/build-wasm/OrthancStoneSingleFrame.js  $outputDir
-  cp $currentDir/build-wasm/OrthancStoneSingleFrame.wasm  $outputDir
-fi
-
-# build single-frame-editor
-if [[ $target == "all" || $target == "OrthancStoneSingleFrameEditor" ]]; then
-  cp $samplesRootDir/Web/single-frame-editor.html $outputDir
-  tsc --allowJs --project $samplesRootDir/Web/single-frame-editor.tsconfig.json
-  cp $currentDir/build-wasm/OrthancStoneSingleFrameEditor.js  $outputDir
-  cp $currentDir/build-wasm/OrthancStoneSingleFrameEditor.wasm  $outputDir
-fi
-
-# build simple-viewer project
-if [[ $target == "all" || $target == "OrthancStoneSimpleViewer" ]]; then
-  mkdir -p $outputDir/simple-viewer/
-  cp $samplesRootDir/SimpleViewer/Wasm/simple-viewer.html $outputDir/simple-viewer/
-  cp $samplesRootDir/SimpleViewer/Wasm/styles.css $outputDir/simple-viewer/
-  tsc --allowJs --project $samplesRootDir/SimpleViewer/Wasm/tsconfig-simple-viewer.json
-  cp $currentDir/build-wasm/OrthancStoneSimpleViewer.js  $outputDir/simple-viewer/
-  cp $currentDir/build-wasm/OrthancStoneSimpleViewer.wasm  $outputDir/simple-viewer/
-fi
-
-cd $currentDir
--- a/Applications/Samples/Deprecated/build-web.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-#!/bin/bash
-
-set -e
-
-target=${1:-all}
-# this script currently assumes that the wasm code has been built on its side and is availabie in build-wasm/
-
-currentDir=$(pwd)
-samplesRootDir=$(pwd)
-
-echo "*************************************************************************"
-echo "samplesRootDir = $samplesRootDir"
-echo "*************************************************************************"
-
-outputDir=$samplesRootDir/build-web/
-mkdir -p "$outputDir"
-
-# files used by all single files samples
-cp "$samplesRootDir/Web/index.html" "$outputDir"
-cp "$samplesRootDir/Web/samples-styles.css" "$outputDir"
-
-# # build simple-viewer-single-file (obsolete project)
-# if [[ $target == "all" || $target == "OrthancStoneSimpleViewerSingleFile" ]]; then
-#   cp $samplesRootDir/Web/simple-viewer-single-file.html $outputDir
-#   tsc --project $samplesRootDir/Web/simple-viewer-single-file.tsconfig.json --outDir "$outputDir"
-#   browserify \
-#       "$outputDir/Platforms/Wasm/wasm-application-runner.js" \
-#       "$outputDir/Applications/Samples/Web/simple-viewer-single-file.js" \
-#       -o "$outputDir/app-simple-viewer-single-file.js"
-#   cp "$currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.js"  $outputDir
-#   cp "$currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.wasm"  $outputDir
-# fi
-
-# # build single-frame
-# if [[ $target == "all" || $target == "OrthancStoneSingleFrame" ]]; then
-#   cp $samplesRootDir/Web/single-frame.html $outputDir
-#   tsc --project $samplesRootDir/Web/single-frame.tsconfig.json --outDir "$outputDir"
-#   browserify \
-#       "$outputDir/Platforms/Wasm/wasm-application-runner.js" \
-#       "$outputDir/Applications/Samples/Web/single-frame.js" \
-#       -o "$outputDir/app-single-frame.js"
-#   cp "$currentDir/build-wasm/OrthancStoneSingleFrame.js"  $outputDir
-#   cp "$currentDir/build-wasm/OrthancStoneSingleFrame.wasm"  $outputDir
-# fi
-
-# build single-frame-editor
-if [[ $target == "all" || $target == "OrthancStoneSingleFrameEditor" ]]; then
-  cp $samplesRootDir/Web/single-frame-editor.html $outputDir
-  tsc --project $samplesRootDir/Web/single-frame-editor.tsconfig.json --outDir "$outputDir"
-  browserify \
-      "$outputDir/Platforms/Wasm/wasm-application-runner.js" \
-      "$outputDir/Applications/Samples/Web/single-frame-editor.js" \
-      -o "$outputDir/app-single-frame-editor.js"
-  cp "$currentDir/build-wasm/OrthancStoneSingleFrameEditor.js"  $outputDir
-  cp "$currentDir/build-wasm/OrthancStoneSingleFrameEditor.wasm"  $outputDir
-fi
-
-# build simple-viewer project
-if [[ $target == "all" || $target == "OrthancStoneSimpleViewer" ]]; then
-  mkdir -p $outputDir/simple-viewer/
-  cp $samplesRootDir/SimpleViewer/Wasm/simple-viewer.html $outputDir/simple-viewer/
-  cp $samplesRootDir/SimpleViewer/Wasm/styles.css $outputDir/simple-viewer/
-  
-  # the root dir must contain all the source files for the whole project
-  tsc --module commonjs --allowJs --project "$samplesRootDir/SimpleViewer/Wasm/tsconfig-simple-viewer.json" --rootDir "$samplesRootDir/../.." --outDir "$outputDir/simple-viewer/"
-  browserify \
-    "$outputDir/simple-viewer/Platforms/Wasm/wasm-application-runner.js" \
-    "$outputDir/simple-viewer/Applications/Samples/SimpleViewer/Wasm/simple-viewer.js" \
-    -o "$outputDir/simple-viewer/app-simple-viewer.js"
-  cp "$currentDir/build-wasm/OrthancStoneSimpleViewer.js"  "$outputDir/simple-viewer/"
-  cp "$currentDir/build-wasm/OrthancStoneSimpleViewer.wasm"  "$outputDir/simple-viewer/"
-fi
-
-cd $currentDir
--- a/Applications/Samples/Deprecated/get-requirements-windows.ps1	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-
-if ($true) {
-
-    Write-Error "This script is obsolete. Please work under WSL and run build-wasm.sh"
-
-} else {
-
-    param(
-        [IO.DirectoryInfo] $EmsdkRootDir = "C:\Emscripten",
-        [bool] $Overwrite = $false
-      )
-    
-    if (Test-Path -Path $EmsdkRootDir) {
-        if( $Override) {
-            Remove-Item -Path $EmsdkRootDir -Force -Recurse
-        } else {
-            throw "The `"$EmsdkRootDir`" folder may not exist! Use the Overwrite flag to bypass this check."
-        }
-    }
-    
-    # TODO: detect whether git is installed
-    # choco install -y git
-    
-    Write-Host "Will retrieve the Emscripten SDK to the `"$EmsdkRootDir`" folder"
-    
-    $EmsdkParentDir = split-path -Parent $EmsdkRootDir
-    $EmsdkRootName = split-path -Leaf $EmsdkRootDir
-    
-    Push-Location $EmsdkParentDir
-    
-    git clone https://github.com/juj/emsdk.git $EmsdkRootName
-    cd $EmsdkRootName
-    
-    git pull
-    
-    ./emsdk install latest
-    
-    ./emsdk activate latest
-    
-    echo "INFO: the ~/.emscripten file has been configured for this installation of Emscripten."
-    
-    Write-Host "emsdk is now installed in $EmsdkRootDir"
-    
-    Pop-Location
-
-}
-
-
-
-
--- a/Applications/Samples/Deprecated/nginx.local.conf	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-# Local config to serve the WASM samples static files and reverse proxy Orthanc.
-# Uses port 9977 instead of 80.
-
-# `events` section is mandatory
-events {
-  worker_connections 1024; # Default: 1024
-}
-
-http {
-
-  # prevent nginx sync issues on OSX
-  proxy_buffering off;
-
-  server {
-    listen 9977 default_server;
-    client_max_body_size 4G;
-
-    # location may have to be adjusted depending on your OS and nginx install
-    include /etc/nginx/mime.types;
-    # if not in your system mime.types, add this line to support WASM:
-    # types {
-    #    application/wasm                      wasm; 
-    # }
-
-    # serve WASM static files
-    root build-web/;
-    location / {
-	}
-
-    # reverse proxy orthanc
-	location /orthanc/ {
-		rewrite /orthanc(.*) $1 break;
-		proxy_pass http://127.0.0.1:8042;
-		proxy_set_header Host $http_host;
-		proxy_set_header my-auth-header good-token;
-		proxy_request_buffering off;
-		proxy_max_temp_file_size 0;
-		client_max_body_size 0;
-	}
-
-
-  }
-  
-}
--- a/Applications/Samples/Deprecated/package-lock.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-{
-  "requires": true,
-  "lockfileVersion": 1,
-  "dependencies": {
-    "typescript": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz",
-      "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg=="
-    }
-  }
-}
--- a/Applications/Samples/Deprecated/rt-viewer-demo/CMakeLists.txt	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-cmake_minimum_required(VERSION 2.8.3)
-project(RtViewerDemo)
-
-if(MSVC)
-  add_definitions(/MP)
-  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
-    add_definitions(/JMC)
-  endif()
-endif()
-
-message("-------------------------------------------------------------------------------------------------------------------")
-message("ORTHANC_FRAMEWORK_ROOT is set to ${ORTHANC_FRAMEWORK_ROOT}")
-message("-------------------------------------------------------------------------------------------------------------------")
-
-if(NOT DEFINED ORTHANC_FRAMEWORK_ROOT)
-  message(FATAL_ERROR "The location of the Orthanc source repository must be set in the ORTHANC_FRAMEWORK_ROOT CMake variable")
-endif()
-
-message("-------------------------------------------------------------------------------------------------------------------")
-message("STONE_SOURCES_DIR is set to ${STONE_SOURCES_DIR}")
-message("-------------------------------------------------------------------------------------------------------------------")
-
-if(NOT DEFINED STONE_SOURCES_DIR)
-  message(FATAL_ERROR "The location of the Stone of Orthanc source repository must be set in the STONE_SOURCES_DIR CMake variable")
-endif()
-
-include(${STONE_SOURCES_DIR}/Resources/CMake/OrthancStoneParameters.cmake)
-
-if (OPENSSL_NO_CAPIENG)
-add_definitions(-DOPENSSL_NO_CAPIENG=1)
-endif()
-
-set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
-set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
-set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
-
-if (ENABLE_WASM)
-  #####################################################################
-  ## Configuration of the Emscripten compiler for WebAssembly target
-  #####################################################################
-
-  set(WASM_FLAGS "-s WASM=1")
-  set(WASM_FLAGS "${WASM_FLAGS} -s STRICT=1") # drops support for all deprecated build options
-  set(WASM_FLAGS "${WASM_FLAGS} -s FILESYSTEM=1") # if we don't include it, gen_uuid.c fails to build because srand, getpid(), ... are not defined
-  set(WASM_FLAGS "${WASM_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0") # actually enable exception catching 
-  set(WASM_FLAGS "${WASM_FLAGS} -s ERROR_ON_MISSING_LIBRARIES=1")
-
-  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
-    set(WASM_FLAGS "${WASM_FLAGS} -g4") # generate debug information
-    set(WASM_FLAGS "${WASM_FLAGS} -s ASSERTIONS=2") # more runtime checks
-  else()
-    set(WASM_FLAGS "${WASM_FLAGS} -Os") # optimize for web (speed and size)
-  endif()
-
-  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
-
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
-
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_FLAGS}")  # not always clear which flags are for the compiler and which one are for the linker -> pass them all to the linker too
-  # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"'")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=128000000")
-
-  add_definitions(-DORTHANC_ENABLE_WASM=1)
-  set(ORTHANC_SANDBOXED ON)
-
-elseif (ENABLE_QT OR ENABLE_SDL)
-
-  set(ENABLE_NATIVE ON)
-  set(ORTHANC_SANDBOXED OFF)
-  set(ENABLE_CRYPTO_OPTIONS ON)
-  set(ENABLE_GOOGLE_TEST ON)
-  set(ENABLE_WEB_CLIENT ON)
-
-endif()
-
-
-#####################################################################
-## Configuration for Orthanc
-#####################################################################
-
-if (ORTHANC_STONE_VERSION STREQUAL "mainline")
-  set(ORTHANC_FRAMEWORK_VERSION "mainline")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
-else()
-  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
-  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
-endif()
-
-set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
-set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
-set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
-
-add_definitions(
-  -DORTHANC_ENABLE_LOGGING_PLUGIN=0
-  )
-
-
-#####################################################################
-## Build a static library containing the Orthanc Stone framework
-#####################################################################
-
-LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
-
-include(${STONE_SOURCES_DIR}/Resources/CMake/OrthancStoneConfiguration.cmake)
-
-add_library(OrthancStone STATIC
-  ${ORTHANC_STONE_SOURCES}
-  )
-
-#####################################################################
-## Build all the sample applications
-#####################################################################
-
-include_directories(${ORTHANC_STONE_ROOT})
-
-list(APPEND RTVIEWERDEMO_APPLICATION_SOURCES
-  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
-  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
-  )
-
-if (ENABLE_WASM)
-  list(APPEND RTVIEWERDEMO_APPLICATION_SOURCES
-    ${STONE_WASM_SOURCES}
-    )
-endif()
-
-add_executable(RtViewerDemo
-  main.cpp
-  ${RTVIEWERDEMO_APPLICATION_SOURCES}
-)
-set_target_properties(RtViewerDemo PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=3)
-target_include_directories(RtViewerDemo PRIVATE ${ORTHANC_STONE_ROOT})
-target_link_libraries(RtViewerDemo OrthancStone)
-
--- a/Applications/Samples/Deprecated/rt-viewer-demo/build-sdl-msvc15.ps1	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-if (-not (Test-Path "build-sdl-msvc15")) {
-  mkdir -p "build-sdl-msvc15"
-}
-
-cd build-sdl-msvc15
-
-cmake -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DOPENSSL_NO_CAPIENG=ON -DORTHANC_FRAMEWORK_SOURCE=path -DSTONE_SOURCES_DIR="$($pwd)\..\..\..\.." -DORTHANC_FRAMEWORK_ROOT="$($pwd)\..\..\..\..\..\orthanc" -DALLOW_DOWNLOADS=ON -DENABLE_SDL=ON .. 
-
-if (!$?) {
-	Write-Error 'cmake configuration failed' -ErrorAction Stop
-}
-
-cmake --build . --target RtViewerDemo --config Debug
-
-if (!$?) {
-	Write-Error 'cmake build failed' -ErrorAction Stop
-}
-
-cd Debug
-
-.\RtViewerDemo.exe --ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa --dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb --struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
-
-
-
--- a/Applications/Samples/Deprecated/rt-viewer-demo/build-wasm.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-#!/bin/bash
-#
-# usage:
-# build-wasm BUILD_TYPE
-# where BUILD_TYPE is Debug, RelWithDebInfo or Release
-
-set -e
-
-buildType=${1:-Debug}
-
-currentDir=$(pwd)
-currentDirAbs=$(realpath $currentDir)
-
-mkdir -p build-wasm
-cd build-wasm
-
-source ~/apps/emsdk/emsdk_env.sh
-cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake \
--DCMAKE_BUILD_TYPE=$buildType -DSTONE_SOURCES_DIR=$currentDirAbs/../../../../orthanc-stone \
--DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDirAbs/../../../../orthanc \
--DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
-
-ninja $target
-
-echo "-- building the web application -- "
-cd $currentDir
-./build-web.sh
-
-echo "Launch start-serving-files.sh to access the web sample application locally"
--- a/Applications/Samples/Deprecated/rt-viewer-demo/build-web.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#!/bin/bash
-
-set -e
-
-target=${1:-all}
-# this script currently assumes that the wasm code has been built on its side and is availabie in build-wasm/
-
-currentDir=$(pwd)
-samplesRootDir=$(pwd)
-
-tscOutput=$samplesRootDir/build-tsc-output/
-outputDir=$samplesRootDir/build-web/
-mkdir -p "$outputDir"
-
-# files used by all single files samples
-cp "$samplesRootDir/index.html" "$outputDir"
-cp "$samplesRootDir/samples-styles.css" "$outputDir"
-
-# build rt-viewer-demo
-cp $samplesRootDir/rt-viewer-demo.html $outputDir
-tsc --project $samplesRootDir/rt-viewer-demo.tsconfig.json --outDir "$tscOutput"
-browserify \
-    "$tscOutput/orthanc-stone/Platforms/Wasm/logger.js" \
-    "$tscOutput/orthanc-stone/Platforms/Wasm/stone-framework-loader.js" \
-    "$tscOutput/orthanc-stone/Platforms/Wasm/wasm-application-runner.js" \
-    "$tscOutput/orthanc-stone/Platforms/Wasm/wasm-viewport.js" \
-    "$tscOutput/rt-viewer-sample/rt-viewer-demo.js" \
-    -o "$outputDir/app-rt-viewer-demo.js"
-cp "$currentDir/build-wasm/RtViewerDemo.js"  $outputDir
-cp "$currentDir/build-wasm/RtViewerDemo.wasm"  $outputDir
-
-cd $currentDir
--- a/Applications/Samples/Deprecated/rt-viewer-demo/index.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <!-- Disable pinch zoom on mobile devices -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta name="HandheldFriendly" content="true" />
-
-    <title>Wasm Samples</title>
-
-<body>
-    <ul>
-      <li><a href="rt-viewer-demo.html?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa&dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb&struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9">RTSTRUCT + CT + RTDOSE viewer demo. Pplease replace the url arguments with suitable IDs (you can find those in the Orthanc Explorer, for instance)</a></li>
-    </ul>
-</body>
-
-</html>
--- a/Applications/Samples/Deprecated/rt-viewer-demo/main.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,893 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "Applications/IStoneApplication.h"
-#include "Framework/Widgets/WorldSceneWidget.h"
-#include "Framework/Widgets/LayoutWidget.h"
-
-#if ORTHANC_ENABLE_WASM==1
-  #include "Platforms/Wasm/WasmPlatformApplicationAdapter.h"
-  #include "Platforms/Wasm/Defaults.h"
-  #include "Platforms/Wasm/WasmViewport.h"
-#endif
-
-#if ORTHANC_ENABLE_QT==1
-  #include "Qt/SampleMainWindow.h"
-  #include "Qt/SampleMainWindowWithButtons.h"
-#endif
-
-#include "Framework/Layers/DicomSeriesVolumeSlicer.h"
-#include "Framework/Widgets/SliceViewerWidget.h"
-#include "Framework/Volumes/StructureSetLoader.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <Core/Images/ImageTraits.h>
-
-#include <boost/math/constants/constants.hpp>
-#include "Framework/dev.h"
-#include "Framework/Widgets/LayoutWidget.h"
-#include "Framework/Layers/DicomStructureSetSlicer.h"
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    class RtViewerDemoBaseApplication : public IStoneApplication
-    {
-    protected:
-      // ownership is transferred to the application context
-#ifndef RESTORE_NON_RTVIEWERDEMO_BEHAVIOR
-      LayoutWidget*          mainWidget_;
-#else
-      WorldSceneWidget*  mainWidget_;
-#endif
-
-    public:
-      virtual void Initialize(StoneApplicationContext* context,
-                              IStatusBar& statusBar,
-                              const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE
-      {
-      }
-
-      virtual std::string GetTitle() const ORTHANC_OVERRIDE
-      {
-        return "Stone of Orthanc - Sample";
-      }
-
-      /**
-       * In the basic samples, the commands are handled by the platform adapter and NOT
-       * by the application handler
-      */
-      virtual void HandleSerializedMessage(const char* data) ORTHANC_OVERRIDE {};
-
-
-      virtual void Finalize() ORTHANC_OVERRIDE {}
-      virtual IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainWidget_;}
-
-#if ORTHANC_ENABLE_WASM==1
-      // default implementations for a single canvas named "canvas" in the HTML and an empty WasmApplicationAdapter
-
-      virtual void InitializeWasm() ORTHANC_OVERRIDE
-      {
-        AttachWidgetToWasmViewport("canvas", mainWidget_);
-      }
-
-      virtual WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(MessageBroker& broker)
-      {
-        return new WasmPlatformApplicationAdapter(broker, *this);
-      }
-#endif
-
-    };
-
-    // this application actually works in Qt and WASM
-    class RtViewerDemoBaseSingleCanvasWithButtonsApplication : public RtViewerDemoBaseApplication
-    {
-public:
-      virtual void OnPushButton1Clicked() {}
-      virtual void OnPushButton2Clicked() {}
-      virtual void OnTool1Clicked() {}
-      virtual void OnTool2Clicked() {}
-
-      virtual void GetButtonNames(std::string& pushButton1,
-                                  std::string& pushButton2,
-                                  std::string& tool1,
-                                  std::string& tool2
-                                  ) {
-        pushButton1 = "action1";
-        pushButton2 = "action2";
-        tool1 = "tool1";
-        tool2 = "tool2";
-      }
-
-#if ORTHANC_ENABLE_QT==1
-      virtual QStoneMainWindow* CreateQtMainWindow() {
-        return new SampleMainWindowWithButtons(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
-      }
-#endif
-
-    };
-
-    // this application actually works in SDL and WASM
-    class RtViewerDemoBaseApplicationSingleCanvas : public RtViewerDemoBaseApplication
-    {
-public:
-
-#if ORTHANC_ENABLE_QT==1
-      virtual QStoneMainWindow* CreateQtMainWindow() {
-        return new SampleMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
-      }
-#endif
-    };
-  }
-}
-
-
-
-namespace OrthancStone
-{
-  namespace Samples
-  {
-    template <Orthanc::PixelFormat T>
-    void ReadDistributionInternal(std::vector<float>& distribution,
-                                  const Orthanc::ImageAccessor& image)
-    {
-      const unsigned int width = image.GetWidth();
-      const unsigned int height = image.GetHeight();
-      
-      distribution.resize(width * height);
-      size_t pos = 0;
-
-      for (unsigned int y = 0; y < height; y++)
-      {
-        for (unsigned int x = 0; x < width; x++, pos++)
-        {
-          distribution[pos] = Orthanc::ImageTraits<T>::GetFloatPixel(image, x, y);
-        }
-      }
-    }
-
-    void ReadDistribution(std::vector<float>& distribution,
-                          const Orthanc::ImageAccessor& image)
-    {
-      switch (image.GetFormat())
-      {
-        case Orthanc::PixelFormat_Grayscale8:
-          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale8>(distribution, image);
-          break;
-
-        case Orthanc::PixelFormat_Grayscale16:
-          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale16>(distribution, image);
-          break;
-
-        case Orthanc::PixelFormat_SignedGrayscale16:
-          ReadDistributionInternal<Orthanc::PixelFormat_SignedGrayscale16>(distribution, image);
-          break;
-
-        case Orthanc::PixelFormat_Grayscale32:
-          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale32>(distribution, image);
-          break;
-
-        case Orthanc::PixelFormat_Grayscale64:
-          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale64>(distribution, image);
-          break;
-
-        default:
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-      }
-    }
-
-
-    class DoseInteractor : public VolumeImageInteractor
-    {
-    private:
-      SliceViewerWidget&         widget_;
-      size_t               layer_;
-      DicomFrameConverter  converter_;
-
-
-      
-    protected:
-      virtual void NotifySliceChange(const ISlicedVolume& slicedVolume,
-                                    const size_t& sliceIndex,
-                                    const Slice& slice)
-      {
-        converter_ = slice.GetConverter();
-        
-  #if 0
-        const OrthancVolumeImage& volume = dynamic_cast<const OrthancVolumeImage&>(slicedVolume);
-
-        RenderStyle s = widget_.GetLayerStyle(layer_);
-
-        if (volume.FitWindowingToRange(s, slice.GetConverter()))
-        {
-          printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
-          widget_.SetLayerStyle(layer_, s);
-        }
-  #endif
-      }
-
-      virtual void NotifyVolumeReady(const ISlicedVolume& slicedVolume)
-      {
-        const float percentile = 0.01f;
-        const OrthancVolumeImage& volume = dynamic_cast<const OrthancVolumeImage&>(slicedVolume);
-
-        std::vector<float> distribution;
-        ReadDistribution(distribution, volume.GetImage().GetInternalImage());
-        std::sort(distribution.begin(), distribution.end());
-
-        int start = static_cast<int>(std::ceil(distribution.size() * percentile));
-        int end = static_cast<int>(std::floor(distribution.size() * (1.0f - percentile)));
-
-        float a = 0;
-        float b = 0;
-        
-        if (start < end &&
-            start >= 0 &&
-            end < static_cast<int>(distribution.size()))
-        {
-          a = distribution[start];
-          b = distribution[end];
-        }
-        else if (!distribution.empty())
-        {
-          // Too small distribution: Use full range
-          a = distribution.front();
-          b = distribution.back();
-        }
-
-        //printf("%f %f\n", a, b);
-
-        RenderStyle s = widget_.GetLayerStyle(layer_);
-        s.windowing_ = ImageWindowing_Custom;
-        s.customWindowCenter_ = static_cast<float>(converter_.Apply((a + b) / 2.0f));
-        s.customWindowWidth_ = static_cast<float>(converter_.Apply(b - a));
-        
-        // 96.210556 => 192.421112
-        widget_.SetLayerStyle(layer_, s);
-        printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);      
-      }
-
-    public:
-      DoseInteractor(MessageBroker& broker, OrthancVolumeImage& volume,
-                    SliceViewerWidget& widget,
-                    VolumeProjection projection,
-                    size_t layer) :
-        VolumeImageInteractor(broker, volume, widget, projection),
-        widget_(widget),
-        layer_(layer)
-      {
-      }
-    };
-
-    class RtViewerDemoApplication :
-      public RtViewerDemoBaseApplicationSingleCanvas,
-      public IObserver
-    {
-    public:
-      std::vector<std::pair<SliceViewerWidget*, size_t> > doseCtWidgetLayerPairs_;
-      std::list<OrthancStone::IWorldSceneInteractor*>    interactors_;
-
-      class Interactor : public IWorldSceneInteractor
-      {
-      private:
-        RtViewerDemoApplication&  application_;
-
-      public:
-        Interactor(RtViewerDemoApplication&  application) :
-          application_(application)
-        {
-        }
-
-        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-          const ViewportGeometry& view,
-          MouseButton button,
-          KeyboardModifiers modifiers,
-          int viewportX,
-          int viewportY,
-          double x,
-          double y,
-          IStatusBar* statusBar,
-          const std::vector<Touch>& displayTouches)
-        {
-          return NULL;
-        }
-
-        virtual void MouseOver(CairoContext& context,
-          WorldSceneWidget& widget,
-          const ViewportGeometry& view,
-          double x,
-          double y,
-          IStatusBar* statusBar)
-        {
-          if (statusBar != NULL)
-          {
-            Vector p = dynamic_cast<SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
-
-            char buf[64];
-            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
-              p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
-            statusBar->SetMessage(buf);
-          }
-        }
-
-        virtual void MouseWheel(WorldSceneWidget& widget,
-          MouseWheelDirection direction,
-          KeyboardModifiers modifiers,
-          IStatusBar* statusBar)
-        {
-          int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
-
-          switch (direction)
-          {
-          case MouseWheelDirection_Up:
-            application_.OffsetSlice(-scale);
-            break;
-
-          case MouseWheelDirection_Down:
-            application_.OffsetSlice(scale);
-            break;
-
-          default:
-            break;
-          }
-        }
-
-        virtual void KeyPressed(WorldSceneWidget& widget,
-          KeyboardKeys key,
-          char keyChar,
-          KeyboardModifiers modifiers,
-          IStatusBar* statusBar)
-        {
-          switch (keyChar)
-          {
-          case 's':
-            // TODO: recursively traverse children
-            widget.FitContent();
-            break;
-
-          default:
-            break;
-          }
-        }
-      };
-
-      void OffsetSlice(int offset)
-      {
-        if (source_ != NULL)
-        {
-          int slice = static_cast<int>(slice_) + offset;
-
-          if (slice < 0)
-          {
-            slice = 0;
-          }
-
-          if (slice >= static_cast<int>(source_->GetSliceCount()))
-          {
-            slice = static_cast<int>(source_->GetSliceCount()) - 1;
-          }
-
-          if (slice != static_cast<int>(slice_))
-          {
-            SetSlice(slice);
-          }
-        }
-      }
-
-
-      SliceViewerWidget& GetMainWidget()
-      {
-        return *dynamic_cast<SliceViewerWidget*>(mainWidget_);
-      }
-
-
-      void SetSlice(size_t index)
-      {
-        if (source_ != NULL &&
-          index < source_->GetSliceCount())
-        {
-          slice_ = static_cast<unsigned int>(index);
-
-#if 1
-          GetMainWidget().SetSlice(source_->GetSlice(slice_).GetGeometry());
-#else
-          // TEST for scene extents - Rotate the axes
-          double a = 15.0 / 180.0 * boost::math::constants::pi<double>();
-
-#if 1
-          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
-          Vector y; GeometryToolbox::AssignVector(y, -sin(a), cos(a), 0);
-#else
-          // Flip the normal
-          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
-          Vector y; GeometryToolbox::AssignVector(y, sin(a), -cos(a), 0);
-#endif
-
-          SliceGeometry s(source_->GetSlice(slice_).GetGeometry().GetOrigin(), x, y);
-          widget_->SetSlice(s);
-#endif
-        }
-      }
-
-
-      void OnMainWidgetGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
-      {
-        // Once the geometry of the series is downloaded from Orthanc,
-        // display its middle slice, and adapt the viewport to fit this
-        // slice
-        if (source_ == &message.GetOrigin())
-        {
-          SetSlice(source_->GetSliceCount() / 2);
-        }
-
-        GetMainWidget().FitContent();
-      }
-
-    DicomFrameConverter                                converter_;
-
-    void OnSliceContentChangedMessage(const ISlicedVolume::SliceContentChangedMessage&   message)
-    {
-      converter_ = message.GetSlice().GetConverter();
-    }
-
-    void OnVolumeReadyMessage(const ISlicedVolume::VolumeReadyMessage& message)
-    {
-      const float percentile = 0.01f;
-
-      auto& slicedVolume = message.GetOrigin();
-      const OrthancVolumeImage& volume = dynamic_cast<const OrthancVolumeImage&>(slicedVolume);
-
-      std::vector<float> distribution;
-      ReadDistribution(distribution, volume.GetImage().GetInternalImage());
-      std::sort(distribution.begin(), distribution.end());
-
-      int start = static_cast<int>(std::ceil(distribution.size() * percentile));
-      int end = static_cast<int>(std::floor(distribution.size() * (1.0f - percentile)));
-
-      float a = 0;
-      float b = 0;
-
-      if (start < end &&
-        start >= 0 &&
-        end < static_cast<int>(distribution.size()))
-      {
-        a = distribution[start];
-        b = distribution[end];
-      }
-      else if (!distribution.empty())
-      {
-        // Too small distribution: Use full range
-        a = distribution.front();
-        b = distribution.back();
-      }
-
-      //printf("WINDOWING %f %f\n", a, b);
-
-      for (const auto& pair : doseCtWidgetLayerPairs_)
-      {
-        auto widget = pair.first;
-        auto layer = pair.second;
-        RenderStyle s = widget->GetLayerStyle(layer);
-        s.windowing_ = ImageWindowing_Custom;
-        s.customWindowCenter_ = static_cast<float>(converter_.Apply((a + b) / 2.0f));
-        s.customWindowWidth_ = static_cast<float>(converter_.Apply(b - a));
-
-        // 96.210556 => 192.421112
-        widget->SetLayerStyle(layer, s);
-        printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
-      }
-    }
-      
-
-
-      size_t AddDoseLayer(SliceViewerWidget& widget,
-        OrthancVolumeImage& volume, VolumeProjection projection);
-
-      void AddStructLayer(
-        SliceViewerWidget& widget, StructureSetLoader& loader);
-
-      SliceViewerWidget* CreateDoseCtWidget(
-        std::unique_ptr<OrthancVolumeImage>& ct,
-        std::unique_ptr<OrthancVolumeImage>& dose,
-        std::unique_ptr<StructureSetLoader>& structLoader,
-        VolumeProjection projection);
-
-      void AddCtLayer(SliceViewerWidget& widget, OrthancVolumeImage& volume);
-
-      std::unique_ptr<Interactor>         mainWidgetInteractor_;
-      const DicomSeriesVolumeSlicer*    source_;
-      unsigned int                      slice_;
-
-      std::string                                        ctSeries_;
-      std::string                                        doseInstance_;
-      std::string                                        doseSeries_;
-      std::string                                        structInstance_;
-      std::unique_ptr<OrthancStone::OrthancVolumeImage>    dose_;
-      std::unique_ptr<OrthancStone::OrthancVolumeImage>    ct_;
-      std::unique_ptr<OrthancStone::StructureSetLoader>    struct_;
-
-    public:
-      RtViewerDemoApplication(MessageBroker& broker) :
-        IObserver(broker),
-        source_(NULL),
-        slice_(0)
-      {
-      }
-
-      /*
-      dev options on bgo xps15
-
-      COMMAND LINE
-      --ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa --dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb --struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
-
-      URL PARAMETERS
-      ?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa&dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb&struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
-
-      */
-
-      void ParseParameters(const boost::program_options::variables_map&  parameters)
-      {
-        // Generic
-        {
-          if (parameters.count("verbose"))
-          {
-            Orthanc::Logging::EnableInfoLevel(true);
-            LOG(INFO) << "Verbose logs (info) are enabled";
-          }
-        }
-
-        {
-          if (parameters.count("trace"))
-          {
-            LOG(INFO) << "parameters.count(\"trace\") != 0";
-            Orthanc::Logging::EnableTraceLevel(true);
-            VLOG(1) << "Trace logs (debug) are enabled";
-          }
-        }
-
-        // CT series
-        {
-
-          if (parameters.count("ct-series") != 1)
-          {
-            LOG(ERROR) << "There must be exactly one CT series specified";
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-          }
-          ctSeries_ = parameters["ct-series"].as<std::string>();
-        }
-
-        // RTDOSE 
-        {
-          if (parameters.count("dose-instance") == 1)
-          {
-            doseInstance_ = parameters["dose-instance"].as<std::string>();
-          }
-          else
-          {
-#ifdef BGO_NOT_IMPLEMENTED_YET
-            // Dose series
-            if (parameters.count("dose-series") != 1)
-            {
-              LOG(ERROR) << "the RTDOSE series is missing";
-              throw Orthanc::OrthancException(
-                Orthanc::ErrorCode_ParameterOutOfRange);
-            }
-            doseSeries_ = parameters["ct"].as<std::string>();
-#endif
-            LOG(ERROR) << "the RTSTRUCT instance is missing";
-            throw Orthanc::OrthancException(
-              Orthanc::ErrorCode_ParameterOutOfRange);
-          }
-        }
-        
-        // RTSTRUCT 
-        {
-          if (parameters.count("struct-instance") == 1)
-          {
-            structInstance_ = parameters["struct-instance"].as<std::string>();
-          }
-          else
-          {
-#ifdef BGO_NOT_IMPLEMENTED_YET
-            // Struct series
-            if (parameters.count("struct-series") != 1)
-            {
-              LOG(ERROR) << "the RTSTRUCT series is missing";
-              throw Orthanc::OrthancException(
-                Orthanc::ErrorCode_ParameterOutOfRange);
-            }
-            structSeries_ = parameters["struct-series"].as<std::string>();
-#endif
-            LOG(ERROR) << "the RTSTRUCT instance is missing";
-            throw Orthanc::OrthancException(
-              Orthanc::ErrorCode_ParameterOutOfRange);
-          }
-        }
-      }
-
-      virtual void DeclareStartupOptions(
-        boost::program_options::options_description& options)
-      {
-        boost::program_options::options_description generic(
-          "RtViewerDemo options. Please note that some of these options "
-          "are mutually exclusive");
-        generic.add_options()
-          ("ct-series", boost::program_options::value<std::string>(),
-            "Orthanc ID of the CT series")
-          ("dose-instance", boost::program_options::value<std::string>(), 
-            "Orthanc ID of the RTDOSE instance (incompatible with dose-series)")
-          ("dose-series", boost::program_options::value<std::string>(), 
-            "NOT IMPLEMENTED YET. Orthanc ID of the RTDOSE series (incompatible"
-            " with dose-instance)")
-          ("struct-instance", boost::program_options::value<std::string>(), 
-            "Orthanc ID of the RTSTRUCT instance (incompatible with struct-"
-            "series)")
-          ("struct-series", boost::program_options::value<std::string>(), 
-            "NOT IMPLEMENTED YET. Orthanc ID of the RTSTRUCT (incompatible with"
-            " struct-instance)")
-          ("smooth", boost::program_options::value<bool>()->default_value(true),
-            "Enable bilinear image smoothing")
-          ;
-
-        options.add(generic);
-      }
-
-      virtual void Initialize(
-        StoneApplicationContext*                      context,
-        IStatusBar&                                   statusBar,
-        const boost::program_options::variables_map&  parameters)
-      {
-        using namespace OrthancStone;
-
-        ParseParameters(parameters);
-
-        context_ = context;
-
-        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
-
-        if (!ctSeries_.empty())
-        {
-          printf("CT = [%s]\n", ctSeries_.c_str());
-
-          ct_.reset(new OrthancStone::OrthancVolumeImage(
-            IObserver::GetBroker(), context->GetOrthancApiClient(), false));
-          ct_->ScheduleLoadSeries(ctSeries_);
-          //ct_->ScheduleLoadSeries(
-          //  "a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");
-          //ct_->ScheduleLoadSeries(
-          //  "03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0");
-        }
-
-        if (!doseSeries_.empty() ||
-          !doseInstance_.empty())
-        {
-          dose_.reset(new OrthancStone::OrthancVolumeImage(
-            IObserver::GetBroker(), context->GetOrthancApiClient(), true));
-
-
-          dose_->RegisterObserverCallback(
-            new Callable<RtViewerDemoApplication, ISlicedVolume::VolumeReadyMessage>
-            (*this, &RtViewerDemoApplication::OnVolumeReadyMessage));
-
-          dose_->RegisterObserverCallback(
-            new Callable<RtViewerDemoApplication, ISlicedVolume::SliceContentChangedMessage>
-            (*this, &RtViewerDemoApplication::OnSliceContentChangedMessage));
-
-          if (doseInstance_.empty())
-          {
-            dose_->ScheduleLoadSeries(doseSeries_);
-          }
-          else
-          {
-            dose_->ScheduleLoadInstance(doseInstance_);
-          }
-
-          //dose_->ScheduleLoadInstance(
-            //"830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");  // 1
-          //dose_->ScheduleLoadInstance(
-            //"269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c"); //0522c0001 TCIA
-        }
-
-        if (!structInstance_.empty())
-        {
-          struct_.reset(new OrthancStone::StructureSetLoader(
-            IObserver::GetBroker(), context->GetOrthancApiClient()));
-
-          struct_->ScheduleLoadInstance(structInstance_);
-
-          //struct_->ScheduleLoadInstance(
-            //"54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9");
-          //struct_->ScheduleLoadInstance(
-            //"17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20"); // 0522c0001 TCIA
-        }
-
-        mainWidget_ = new LayoutWidget("main-layout");
-        mainWidget_->SetBackgroundColor(0, 0, 0);
-        mainWidget_->SetBackgroundCleared(true);
-        mainWidget_->SetPadding(0);
-
-        auto axialWidget = CreateDoseCtWidget
-        (ct_, dose_, struct_, OrthancStone::VolumeProjection_Axial);
-        mainWidget_->AddWidget(axialWidget);
-               
-        std::unique_ptr<OrthancStone::LayoutWidget> subLayout(
-          new OrthancStone::LayoutWidget("main-layout"));
-        subLayout->SetVertical();
-        subLayout->SetPadding(5);
-
-        auto coronalWidget = CreateDoseCtWidget
-        (ct_, dose_, struct_, OrthancStone::VolumeProjection_Coronal);
-        subLayout->AddWidget(coronalWidget);
-
-        auto sagittalWidget = CreateDoseCtWidget
-        (ct_, dose_, struct_, OrthancStone::VolumeProjection_Sagittal);
-        subLayout->AddWidget(sagittalWidget);
-        
-        mainWidget_->AddWidget(subLayout.release());
-      }
-    };
-
-
-    size_t RtViewerDemoApplication::AddDoseLayer(
-      SliceViewerWidget& widget,
-      OrthancVolumeImage& volume, VolumeProjection projection)
-    {
-      size_t layer = widget.AddLayer(
-        new VolumeImageMPRSlicer(IObserver::GetBroker(), volume));
-
-      RenderStyle s;
-      //s.drawGrid_ = true;
-      s.SetColor(255, 0, 0);  // Draw missing PET layer in red
-      s.alpha_ = 0.3f;
-      s.applyLut_ = true;
-      s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
-      s.interpolation_ = ImageInterpolation_Bilinear;
-      widget.SetLayerStyle(layer, s);
-
-      return layer;
-    }
-
-    void RtViewerDemoApplication::AddStructLayer(
-      SliceViewerWidget& widget, StructureSetLoader& loader)
-    {
-      widget.AddLayer(new DicomStructureSetSlicer(
-        IObserver::GetBroker(), loader));
-    }
-
-    SliceViewerWidget* RtViewerDemoApplication::CreateDoseCtWidget(
-      std::unique_ptr<OrthancVolumeImage>& ct,
-      std::unique_ptr<OrthancVolumeImage>& dose,
-      std::unique_ptr<StructureSetLoader>& structLoader,
-      VolumeProjection projection)
-    {
-      std::unique_ptr<OrthancStone::SliceViewerWidget> widget(
-        new OrthancStone::SliceViewerWidget(IObserver::GetBroker(),
-          "ct-dose-widget"));
-
-      if (ct.get() != NULL)
-      {
-        AddCtLayer(*widget, *ct);
-      }
-
-      if (dose.get() != NULL)
-      {
-        size_t layer = AddDoseLayer(*widget, *dose, projection);
-
-        // we need to store the dose rendering widget because we'll update them
-        // according to various asynchronous events
-        doseCtWidgetLayerPairs_.push_back(std::make_pair(widget.get(), layer));
-#if 0
-        interactors_.push_back(new VolumeImageInteractor(
-          IObserver::GetBroker(), *dose, *widget, projection));
-#else
-        interactors_.push_back(new DoseInteractor(
-          IObserver::GetBroker(), *dose, *widget, projection, layer));
-#endif
-      }
-      else if (ct.get() != NULL)
-      {
-        interactors_.push_back(
-          new VolumeImageInteractor(
-            IObserver::GetBroker(), *ct, *widget, projection));
-      }
-
-      if (structLoader.get() != NULL)
-      {
-        AddStructLayer(*widget, *structLoader);
-      }
-
-      return widget.release();
-    }
-
-    void RtViewerDemoApplication::AddCtLayer(
-      SliceViewerWidget& widget,
-      OrthancVolumeImage& volume)
-    {
-      size_t layer = widget.AddLayer(
-        new VolumeImageMPRSlicer(IObserver::GetBroker(), volume));
-
-      RenderStyle s;
-      //s.drawGrid_ = true;
-      s.alpha_ = 1;
-      s.windowing_ = ImageWindowing_Bone;
-      widget.SetLayerStyle(layer, s);
-    }
-  }
-}
-
-
-
-#if ORTHANC_ENABLE_WASM==1
-
-#include "Platforms/Wasm/WasmWebService.h"
-#include "Platforms/Wasm/WasmViewport.h"
-
-#include <emscripten/emscripten.h>
-
-//#include "SampleList.h"
-
-
-OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker)
-{
-  return new OrthancStone::Samples::RtViewerDemoApplication(broker);
-}
-
-OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, OrthancStone::IStoneApplication* application)
-{
-  return dynamic_cast<OrthancStone::Samples::RtViewerDemoApplication*>(application)->CreateWasmApplicationAdapter(broker);
-}
-
-#else
-
-//#include "SampleList.h"
-#if ORTHANC_ENABLE_SDL==1
-#include "Applications/Sdl/SdlStoneApplicationRunner.h"
-#endif
-#if ORTHANC_ENABLE_QT==1
-#include "Applications/Qt/SampleQtApplicationRunner.h"
-#endif
-#include "Framework/Messages/MessageBroker.h"
-
-int main(int argc, char* argv[])
-{
-  OrthancStone::MessageBroker broker;
-  OrthancStone::Samples::RtViewerDemoApplication sampleStoneApplication(broker);
-
-#if ORTHANC_ENABLE_SDL==1
-  OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(broker, sampleStoneApplication);
-  return sdlApplicationRunner.Execute(argc, argv);
-#endif
-#if ORTHANC_ENABLE_QT==1
-  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(broker, sampleStoneApplication);
-  return qtAppRunner.Execute(argc, argv);
-#endif
-}
-
-
-#endif
-
-
-
-
-
-
-
--- a/Applications/Samples/Deprecated/rt-viewer-demo/nginx.local.conf	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-# Local config to serve the WASM samples static files and reverse proxy Orthanc.
-# Uses port 9977 instead of 80.
-
-# `events` section is mandatory
-events {
-  worker_connections 1024; # Default: 1024
-}
-
-http {
-
-  # prevent nginx sync issues on OSX
-  proxy_buffering off;
-
-  server {
-    listen 9977 default_server;
-    client_max_body_size 4G;
-
-    # location may have to be adjusted depending on your OS and nginx install
-    include /etc/nginx/mime.types;
-    # if not in your system mime.types, add this line to support WASM:
-    # types {
-    #    application/wasm                      wasm; 
-    # }
-
-    # serve WASM static files
-    root build-web/;
-    location / {
-	}
-
-    # reverse proxy orthanc
-	location /orthanc/ {
-		rewrite /orthanc(.*) $1 break;
-		proxy_pass http://127.0.0.1:8042;
-		proxy_set_header Host $http_host;
-		proxy_set_header my-auth-header good-token;
-		proxy_request_buffering off;
-		proxy_max_temp_file_size 0;
-		client_max_body_size 0;
-	}
-
-
-  }
-  
-}
--- a/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.html	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-<!doctype html>
-
-<html lang="us">
-  <head>
-    <meta charset="utf-8" />
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <!-- Disable pinch zoom on mobile devices -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <meta name="HandheldFriendly" content="true" />
-
-    <title>Simple Viewer</title>
-    <link href="samples-styles.css" rel="stylesheet" />
-
-<body>
-  <div style="width: 100%; height: 5%">
-    <p>RTSTRUCT viewer demonstration</p>
-  </div>
-  <div style="width: 100%; height: 95%">
-    <canvas id="canvas"></canvas>
-  </div>
-  <script type="text/javascript" src="app-rt-viewer-demo.js"></script>
-</body>
-
-</html>
\ No newline at end of file
--- a/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.ts	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-import { InitializeWasmApplication } from '../../../Platforms/Wasm/wasm-application-runner';
-
-
-InitializeWasmApplication("RtViewerDemo", "/orthanc");
-
--- a/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.tsconfig.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-{
-    "extends" : "./tsconfig-samples",
-    "compilerOptions": {
-    },
-    "include" : [
-        "rt-viewer-demo.ts"
-    ]
-}
--- a/Applications/Samples/Deprecated/rt-viewer-demo/samples-styles.css	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-html, body {
-  width: 100%;
-  height: 100%;
-  margin: 0px;
-  border: 0;
-  overflow: hidden; /*  Disable scrollbars */
-  display: block;  /* No floating content on sides */
-  background-color: black;
-  color: white;
-  font-family: Arial, Helvetica, sans-serif;
-}
-
-canvas {
-  left:0px;
-  top:0px;
-}
\ No newline at end of file
--- a/Applications/Samples/Deprecated/rt-viewer-demo/start-serving-files.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-sudo nginx -p $(pwd) -c nginx.local.conf
-
-echo "Please browse to :"
-
-echo "http://localhost:9977/rt-viewer-demo.html?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa&dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb&struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"
-
-echo "(This requires you have uploaded the correct files to your local Orthanc instance)"
--- a/Applications/Samples/Deprecated/rt-viewer-demo/stop-serving-files.sh	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-sudo nginx -s stop
-
--- a/Applications/Samples/Deprecated/rt-viewer-demo/tsconfig-samples.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-{
-    "extends" : "../../../Platforms/Wasm/tsconfig-stone.json",
-    "compilerOptions": {
-        "sourceMap": false,
-        "lib" : [
-            "es2017",
-            "dom",
-            "dom.iterable"
-        ]
-    }
-}
--- a/Applications/Samples/Deprecated/tsconfig-stone.json	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-{
-    "include" : [
-        "../../Platforms/Wasm/stone-framework-loader.ts",
-        "../../Platforms/Wasm/wasm-application-runner.ts",
-        "../../Platforms/Wasm/wasm-viewport.ts"
-    ]
-}
--- a/Applications/Sdl/SdlCairoSurface.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SdlCairoSurface.h"
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-namespace OrthancStone
-{
-  SdlCairoSurface::SdlCairoSurface(SdlWindow& window) :
-    window_(window),
-    sdlSurface_(NULL)
-  {
-  }
-
-
-  SdlCairoSurface::~SdlCairoSurface()
-  {
-    if (sdlSurface_)
-    {
-      SDL_FreeSurface(sdlSurface_);
-    }
-  }
-
-
-  void SdlCairoSurface::SetSize(unsigned int width,
-                                unsigned int height)
-  {
-    if (cairoSurface_.get() == NULL ||
-        cairoSurface_->GetWidth() != width ||
-        cairoSurface_->GetHeight() != height)
-    {
-      cairoSurface_.reset(new CairoSurface(width, height, false /* no alpha */));
-
-      // TODO Big endian?
-      static const uint32_t rmask = 0x00ff0000;
-      static const uint32_t gmask = 0x0000ff00;
-      static const uint32_t bmask = 0x000000ff;
-
-      if (sdlSurface_)
-      {
-        SDL_FreeSurface(sdlSurface_);
-      }
-
-      sdlSurface_ = SDL_CreateRGBSurfaceFrom(cairoSurface_->GetBuffer(), width, height, 32,
-                                             cairoSurface_->GetPitch(), rmask, gmask, bmask, 0);
-      if (!sdlSurface_)
-      {
-        LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface";
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-    }
-  }
-
-
-  void SdlCairoSurface::Render(Deprecated::IViewport& viewport)
-  {
-    if (cairoSurface_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    Orthanc::ImageAccessor target;
-    cairoSurface_->GetWriteableAccessor(target);
-
-    if (viewport.Render(target))
-    {
-      window_.Render(sdlSurface_);
-    }
-  }
-}
-
-#endif
--- a/Applications/Sdl/SdlCairoSurface.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include "../../Framework/Viewport/SdlWindow.h"
-#include "../../Framework/Wrappers/CairoSurface.h"
-#include "../../Framework/Deprecated/Viewport/IViewport.h"
-
-#include <Core/Compatibility.h>
-
-#include <SDL_render.h>
-#include <boost/thread/mutex.hpp>
-
-namespace OrthancStone
-{
-  class SdlCairoSurface : public boost::noncopyable
-  {
-  private:
-    std::unique_ptr<CairoSurface>  cairoSurface_;
-    SdlWindow&                   window_;
-    SDL_Surface*                 sdlSurface_;
-
-  public:
-    SdlCairoSurface(SdlWindow& window);
-
-    ~SdlCairoSurface();
-
-    void SetSize(unsigned int width,
-                 unsigned int height);
-
-    void Render(Deprecated::IViewport& viewport);
-  };
-}
-
-#endif
--- a/Applications/Sdl/SdlEngine.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SdlEngine.h"
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include <Core/Logging.h>
-
-#include <SDL.h>
-
-namespace OrthancStone
-{
-  void SdlEngine::SetSize(unsigned int width,
-                          unsigned int height)
-  {
-    NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
-    locker.GetCentralViewport().SetSize(width, height);
-    surface_.SetSize(width, height);
-  }
-
-
-  void SdlEngine::RenderFrame()
-  {
-    if (viewportChanged_)
-    {
-      NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
-      surface_.Render(locker.GetCentralViewport());
-
-      viewportChanged_ = false;
-    }
-  }
-
-
-  KeyboardModifiers SdlEngine::GetKeyboardModifiers(const uint8_t* keyboardState,
-                                                    const int scancodeCount)
-  {
-    int result = KeyboardModifiers_None;
-
-    if (keyboardState != NULL)
-    {
-      if (SDL_SCANCODE_LSHIFT < scancodeCount &&
-          keyboardState[SDL_SCANCODE_LSHIFT])
-      {
-        result |= KeyboardModifiers_Shift;
-      }
-
-      if (SDL_SCANCODE_RSHIFT < scancodeCount &&
-          keyboardState[SDL_SCANCODE_RSHIFT])
-      {
-        result |= KeyboardModifiers_Shift;
-      }
-
-      if (SDL_SCANCODE_LCTRL < scancodeCount &&
-          keyboardState[SDL_SCANCODE_LCTRL])
-      {
-        result |= KeyboardModifiers_Control;
-      }
-
-      if (SDL_SCANCODE_RCTRL < scancodeCount &&
-          keyboardState[SDL_SCANCODE_RCTRL])
-      {
-        result |= KeyboardModifiers_Control;
-      }
-
-      if (SDL_SCANCODE_LALT < scancodeCount &&
-          keyboardState[SDL_SCANCODE_LALT])
-      {
-        result |= KeyboardModifiers_Alt;
-      }
-
-      if (SDL_SCANCODE_RALT < scancodeCount &&
-          keyboardState[SDL_SCANCODE_RALT])
-      {
-        result |= KeyboardModifiers_Alt;
-      }
-    }
-
-    return static_cast<KeyboardModifiers>(result);
-  }
-
-
-  SdlEngine::SdlEngine(SdlWindow& window,
-                       NativeStoneApplicationContext& context) :
-    window_(window),
-    context_(context),
-    surface_(window),
-    viewportChanged_(true)
-  {
-  }
-  
-
-  void SdlEngine::Run()
-  {
-    int scancodeCount = 0;
-    const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
-
-    SetSize(window_.GetWidth(), window_.GetHeight());
-    
-    {
-      NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
-      locker.GetCentralViewport().FitContent();
-    }
-    
-    bool stop = false;
-    while (!stop)
-    {
-      RenderFrame();
-
-      SDL_Event event;
-
-      while (!stop &&
-             SDL_PollEvent(&event))
-      {
-        NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
-
-        if (event.type == SDL_QUIT)
-        {
-          stop = true;
-          break;
-        }
-        else if (event.type == SDL_MOUSEBUTTONDOWN)
-        {
-          KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
-
-          switch (event.button.button)
-          {
-          case SDL_BUTTON_LEFT:
-            locker.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
-            break;
-            
-          case SDL_BUTTON_RIGHT:
-            locker.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
-            break;
-            
-          case SDL_BUTTON_MIDDLE:
-            locker.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
-            break;
-
-          default:
-            break;
-          }
-        }
-        else if (event.type == SDL_MOUSEMOTION)
-        {
-          locker.GetCentralViewport().MouseMove(event.button.x, event.button.y, std::vector<Deprecated::Touch>());
-        }
-        else if (event.type == SDL_MOUSEBUTTONUP)
-        {
-          locker.GetCentralViewport().MouseUp();
-        }
-        else if (event.type == SDL_WINDOWEVENT)
-        {
-          switch (event.window.event)
-          {
-          case SDL_WINDOWEVENT_LEAVE:
-            locker.GetCentralViewport().MouseLeave();
-            break;
-
-          case SDL_WINDOWEVENT_ENTER:
-            locker.GetCentralViewport().MouseEnter();
-            break;
-
-          case SDL_WINDOWEVENT_SIZE_CHANGED:
-            SetSize(event.window.data1, event.window.data2);
-            break;
-
-          default:
-            break;
-          }
-        }
-        else if (event.type == SDL_MOUSEWHEEL)
-        {
-          KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
-
-          int x, y;
-          SDL_GetMouseState(&x, &y);
-
-          if (event.wheel.y > 0)
-          {
-            locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers);
-          }
-          else if (event.wheel.y < 0)
-          {
-            locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
-          }
-        }
-        else if (event.type == SDL_KEYDOWN &&
-                 event.key.repeat == 0 /* Ignore key bounce */)
-        {
-          KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
-
-          switch (event.key.keysym.sym)
-          {
-          case SDLK_a:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'a', modifiers);  break;
-          case SDLK_b:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'b', modifiers);  break;
-          case SDLK_c:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'c', modifiers);  break;
-          case SDLK_d:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'd', modifiers);  break;
-          case SDLK_e:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'e', modifiers);  break;
-          case SDLK_f:    window_.ToggleMaximize();                         break;
-          case SDLK_g:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'g', modifiers);  break;
-          case SDLK_h:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'h', modifiers);  break;
-          case SDLK_i:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'i', modifiers);  break;
-          case SDLK_j:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'j', modifiers);  break;
-          case SDLK_k:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'k', modifiers);  break;
-          case SDLK_l:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'l', modifiers);  break;
-          case SDLK_m:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'm', modifiers);  break;
-          case SDLK_n:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'n', modifiers);  break;
-          case SDLK_o:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'o', modifiers);  break;
-          case SDLK_p:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'p', modifiers);  break;
-          case SDLK_q:    stop = true;                                      break;
-          case SDLK_r:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'r', modifiers);  break;
-          case SDLK_s:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 's', modifiers);  break;
-          case SDLK_t:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 't', modifiers);  break;
-          case SDLK_u:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'u', modifiers);  break;
-          case SDLK_v:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'v', modifiers);  break;
-          case SDLK_w:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'w', modifiers);  break;
-          case SDLK_x:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'x', modifiers);  break;
-          case SDLK_y:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'y', modifiers);  break;
-          case SDLK_z:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'z', modifiers);  break;
-          case SDLK_KP_0: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '0', modifiers);  break;
-          case SDLK_KP_1: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '1', modifiers);  break;
-          case SDLK_KP_2: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '2', modifiers);  break;
-          case SDLK_KP_3: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '3', modifiers);  break;
-          case SDLK_KP_4: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '4', modifiers);  break;
-          case SDLK_KP_5: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '5', modifiers);  break;
-          case SDLK_KP_6: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '6', modifiers);  break;
-          case SDLK_KP_7: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '7', modifiers);  break;
-          case SDLK_KP_8: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '8', modifiers);  break;
-          case SDLK_KP_9: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '9', modifiers);  break;
-
-          case SDLK_PLUS:
-          case SDLK_KP_PLUS:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '+', modifiers);  break;
-
-          case SDLK_MINUS:
-          case SDLK_KP_MINUS:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '-', modifiers);  break;
-
-          case SDLK_DELETE:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Delete, 0, modifiers);  break;
-          case SDLK_BACKSPACE:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Backspace, 0, modifiers);  break;
-          case SDLK_RIGHT:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Right, 0, modifiers);  break;
-          case SDLK_LEFT:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Left, 0, modifiers);  break;
-          case SDLK_UP:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Up, 0, modifiers);  break;
-          case SDLK_DOWN:
-            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Down, 0, modifiers);  break;
-          default:
-            break;
-          }
-        }
-      }
-
-      // Small delay to avoid using 100% of CPU
-      SDL_Delay(1);
-    }
-  }
-}
-
-#endif
--- a/Applications/Sdl/SdlEngine.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include "../../Framework/Messages/ObserverBase.h"
-#include "../Generic/NativeStoneApplicationContext.h"
-#include "SdlCairoSurface.h"
-
-namespace OrthancStone
-{
-  class SdlEngine : public ObserverBase<SdlEngine>
-  {
-  private:
-    SdlWindow&                window_;
-    NativeStoneApplicationContext&  context_;
-    SdlCairoSurface           surface_;
-    bool                      viewportChanged_;
-
-    void SetSize(unsigned int width,
-                 unsigned int height);
-    
-    void RenderFrame();
-
-    static KeyboardModifiers GetKeyboardModifiers(const uint8_t* keyboardState,
-                                                  const int scancodeCount);
-
-  public:
-    SdlEngine(SdlWindow& window,
-              NativeStoneApplicationContext& context);
-  
-    void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
-    {
-      viewportChanged_ = true;
-    }
-
-    void Run();
-  };
-}
-
-#endif
--- a/Applications/Sdl/SdlOrthancSurface.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "SdlOrthancSurface.h"
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <Core/Images/Image.h>
-
-#include <SDL_render.h>
-
-namespace OrthancStone
-{
-  SdlOrthancSurface::SdlOrthancSurface(SdlWindow& window) :
-    window_(window),
-    sdlSurface_(NULL)
-  {
-  }
-
-
-  SdlOrthancSurface::~SdlOrthancSurface()
-  {
-    if (sdlSurface_)
-    {
-      SDL_FreeSurface(sdlSurface_);
-    }
-  }
-
-
-  void SdlOrthancSurface::SetSize(unsigned int width,
-                                  unsigned int height)
-  {
-    if (image_.get() == NULL ||
-        image_->GetWidth() != width ||
-        image_->GetHeight() != height)
-    {
-      image_.reset(new Orthanc::Image(Orthanc::PixelFormat_BGRA32, width, height, true));  // (*)
-
-      if (image_->GetPitch() != image_->GetWidth() * 4)
-      {
-        // This should have been ensured by setting "forceMinimalPitch" to "true" (*)
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-
-      // TODO Big endian?
-      static const uint32_t rmask = 0x00ff0000;
-      static const uint32_t gmask = 0x0000ff00;
-      static const uint32_t bmask = 0x000000ff;
-
-      if (sdlSurface_)
-      {
-        SDL_FreeSurface(sdlSurface_);
-      }
-
-      sdlSurface_ = SDL_CreateRGBSurfaceFrom(image_->GetBuffer(), width, height, 32,
-                                             image_->GetPitch(), rmask, gmask, bmask, 0);
-      if (!sdlSurface_)
-      {
-        LOG(ERROR) << "Cannot create a SDL surface from a Orthanc surface";
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-    }
-  }
-
-
-  Orthanc::ImageAccessor& SdlOrthancSurface::GetImage()
-  {
-    if (image_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    return *image_;
-  }
-
-
-  void SdlOrthancSurface::Render()
-  {
-    if (image_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    window_.Render(sdlSurface_);
-  }
-}
-
-#endif
--- a/Applications/Sdl/SdlOrthancSurface.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#if ORTHANC_ENABLE_SDL == 1
-
-#include "../../Framework/Viewport/SdlWindow.h"
-
-#include <Core/Compatibility.h>
-#include <Core/Images/ImageAccessor.h>
-
-#include <boost/thread/mutex.hpp>
-
-namespace OrthancStone
-{
-  class SdlOrthancSurface : public boost::noncopyable
-  {
-  private:
-    std::unique_ptr<Orthanc::ImageAccessor>  image_;
-    SdlWindow&                             window_;
-    SDL_Surface*                           sdlSurface_;
-
-  public:
-    SdlOrthancSurface(SdlWindow& window);
-
-    ~SdlOrthancSurface();
-
-    void SetSize(unsigned int width,
-                 unsigned int height);
-
-    Orthanc::ImageAccessor& GetImage();
-
-    void Render();
-  };
-}
-
-#endif
--- a/Applications/Sdl/SdlStoneApplicationRunner.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#if ORTHANC_ENABLE_SDL != 1
-#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
-#endif
-
-#include "SdlStoneApplicationRunner.h"
-
-#include "../../Platforms/Generic/OracleWebService.h"
-#include "SdlEngine.h"
-
-#include <Core/Logging.h>
-#include <Core/HttpClient.h>
-#include <Core/Toolbox.h>
-#include <Core/OrthancException.h>
-#include <Plugins/Samples/Common/OrthancHttpConnection.h>
-
-#include <boost/program_options.hpp>
-
-namespace OrthancStone
-{
-  void SdlStoneApplicationRunner::Initialize()
-  {
-    SdlWindow::GlobalInitialize();
-  }
-
-  
-  void SdlStoneApplicationRunner::DeclareCommandLineOptions(boost::program_options::options_description& options)
-  {
-    boost::program_options::options_description sdl("SDL options");
-    sdl.add_options()
-        ("width", boost::program_options::value<int>()->default_value(1024), "Initial width of the SDL window")
-        ("height", boost::program_options::value<int>()->default_value(768), "Initial height of the SDL window")
-        ("opengl", boost::program_options::value<bool>()->default_value(true), "Enable OpenGL in SDL")
-        ;
-
-    options.add(sdl);
-  }
-
-  
-  void SdlStoneApplicationRunner::ParseCommandLineOptions(const boost::program_options::variables_map& parameters)
-  {
-    if (!parameters.count("width") ||
-        !parameters.count("height") ||
-        !parameters.count("opengl"))
-    {
-      LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    int w = parameters["width"].as<int>();
-    int h = parameters["height"].as<int>();
-    if (w <= 0 || h <= 0)
-    {
-      LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    width_ = static_cast<unsigned int>(w);
-    height_ = static_cast<unsigned int>(h);
-    LOG(WARNING) << "Initial display size: " << width_ << "x" << height_;
-
-    enableOpenGl_ = parameters["opengl"].as<bool>();
-    if (enableOpenGl_)
-    {
-      LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes";
-    }
-    else
-    {
-      LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance";
-    }
-  }
-
-  
-  void SdlStoneApplicationRunner::Run(NativeStoneApplicationContext& context,
-                                      const std::string& title,
-                                      int argc,
-                                      char* argv[])
-  {
-    /**************************************************************
-     * Run the application inside a SDL window
-     **************************************************************/
-
-    LOG(WARNING) << "Starting the application";
-
-    SdlWindow window(title.c_str(), width_, height_, enableOpenGl_);
-    boost::shared_ptr<SdlEngine> sdl(new SdlEngine(window, context));
-
-    {
-      NativeStoneApplicationContext::GlobalMutexLocker locker(context);
-
-      sdl->Register<Deprecated::IViewport::ViewportChangedMessage>
-        (locker.GetCentralViewport(), &SdlEngine::OnViewportChanged);
-
-      //context.GetCentralViewport().Register(sdl);  // (*)
-    }
-
-    context.Start();
-    sdl->Run();
-
-    LOG(WARNING) << "Stopping the application";
-
-    // Don't move the "Stop()" command below out of the block,
-    // otherwise the application might crash, because the
-    // "SdlEngine" is an observer of the viewport (*) and the
-    // update thread started by "context.Start()" would call a
-    // destructed object (the "SdlEngine" is deleted with the
-    // lexical scope).
-
-    // TODO Is this still true with message broker?
-    context.Stop();
-  }
-
-  
-  void SdlStoneApplicationRunner::Finalize()
-  {
-    SdlWindow::GlobalFinalize();
-  }
-}
--- a/Applications/Sdl/SdlStoneApplicationRunner.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../Generic/NativeStoneApplicationRunner.h"
-
-#if ORTHANC_ENABLE_SDL != 1
-#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
-#endif
-
-#include <SDL.h>   // Necessary to avoid undefined reference to `SDL_main'
-
-namespace OrthancStone
-{
-  class SdlStoneApplicationRunner : public NativeStoneApplicationRunner
-  {
-  private:
-    unsigned int  width_;
-    unsigned int  height_;
-    bool          enableOpenGl_;
-    
-  public:
-    SdlStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application) :
-      NativeStoneApplicationRunner(application)
-    {
-    }
-
-    virtual void Initialize();
-    
-    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
-    
-    virtual void Run(NativeStoneApplicationContext& context,
-                     const std::string& title,
-                     int argc,
-                     char* argv[]);
-    
-    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters);
-    
-    virtual void Finalize();
-  };
-}
--- a/Applications/StoneApplicationContext.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "StoneApplicationContext.h"
-
-#include <Core/OrthancException.h>
-
-namespace OrthancStone
-{
-  void StoneApplicationContext::InitializeOrthanc()
-  {
-    if (webService_ == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    orthanc_.reset(new Deprecated::OrthancApiClient(*webService_, orthancBaseUrl_));
-  }
-
-
-  boost::shared_ptr<Deprecated::IWebService> StoneApplicationContext::GetWebService()
-  {
-    if (webService_ == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    
-    return webService_;
-  }
-
-  
-  boost::shared_ptr<Deprecated::OrthancApiClient> StoneApplicationContext::GetOrthancApiClient()
-  {
-    if (orthanc_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    
-    return orthanc_;
-  }
-
-  
-  void StoneApplicationContext::SetWebService(boost::shared_ptr<Deprecated::IWebService> webService)
-  {
-    webService_ = webService;
-    InitializeOrthanc();
-  }
-
-
-  void StoneApplicationContext::SetOrthancBaseUrl(const std::string& baseUrl)
-  {
-    // Make sure the base url ends with "/"
-    if (baseUrl.empty() ||
-        baseUrl[baseUrl.size() - 1] != '/')
-    {
-      orthancBaseUrl_ = baseUrl + "/";
-    }
-    else
-    {
-      orthancBaseUrl_ = baseUrl;
-    }
-
-    if (webService_ != NULL)
-    {
-      InitializeOrthanc();
-    }
-  }
-}
--- a/Applications/StoneApplicationContext.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../Framework/Deprecated/Toolbox/IWebService.h"
-#include "../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h"
-#include "../Framework/Deprecated/Toolbox/OrthancApiClient.h"
-#include "../Framework/Deprecated/Viewport/WidgetViewport.h"
-
-
-#ifdef _MSC_VER
-  #if _MSC_VER > 1910
-    #define orthanc_override override
-  #else
-    #define orthanc_override
-  #endif
-#elif defined __GNUC__
-  #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-/* Test for GCC > 3.2.0 */
-  #if GCC_VERSION > 40900
-    #define orthanc_override override
-  #else
-    #define orthanc_override
-  #endif
-#else
-    #define orthanc_override
-#endif
-
-#include <list>
-
-namespace OrthancStone
-{
-  // a StoneApplicationContext contains the services that a StoneApplication
-  // uses and that depends on the environment in which the Application executes.
-  // I.e, the StoneApplicationContext provides a WebService interface such that
-  // the StoneApplication can perform HTTP requests.  In a WASM environment,
-  // the WebService is provided by the browser while, in a native environment,
-  // the WebService is provided by the OracleWebService (a C++ Http client)
-
-  class StoneApplicationContext : public boost::noncopyable
-  {
-  private:
-    boost::shared_ptr<Deprecated::IWebService>     webService_;
-    Deprecated::IDelayedCallExecutor*  delayedCallExecutor_;   // TODO => shared_ptr ??
-    boost::shared_ptr<Deprecated::OrthancApiClient>  orthanc_;
-    std::string                      orthancBaseUrl_;
-
-    void InitializeOrthanc();
-
-  public:
-    StoneApplicationContext() :
-      delayedCallExecutor_(NULL)
-    {
-    }
-
-    virtual ~StoneApplicationContext()
-    {
-    }
-
-    boost::shared_ptr<Deprecated::IWebService> GetWebService();
-
-    boost::shared_ptr<Deprecated::OrthancApiClient> GetOrthancApiClient();
-
-    void SetWebService(boost::shared_ptr<Deprecated::IWebService> webService);
-
-    void SetOrthancBaseUrl(const std::string& baseUrl);
-
-    void SetDelayedCallExecutor(Deprecated::IDelayedCallExecutor& delayedCallExecutor)
-    {
-      delayedCallExecutor_ = &delayedCallExecutor;
-    }
-
-    Deprecated::IDelayedCallExecutor& GetDelayedCallExecutor()
-    {
-      return *delayedCallExecutor_;
-    }
-  };
-}
--- a/Applications/Wasm/StartupParametersBuilder.cpp	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-#include "StartupParametersBuilder.h"
-#include <iostream>
-#include <cstdio>
-#include "emscripten/html5.h"
-
-namespace OrthancStone
-{
-  void StartupParametersBuilder::Clear()
-  {
-    startupParameters_.clear();
-  }
-
-  void StartupParametersBuilder::SetStartupParameter(
-    const char* name,
-    const char* value)
-  {
-    startupParameters_.push_back(std::make_tuple(name, value));
-  }
-
-  void StartupParametersBuilder::GetStartupParameters(
-    boost::program_options::variables_map& parameters,
-    const boost::program_options::options_description& options) 
-  {
-    std::vector<std::string> argvStrings(startupParameters_.size() + 1);
-    // argv mirrors pointers to the internal argvStrings buffers.
-    // ******************************************************
-    // THIS IS HIGHLY DANGEROUS SO BEWARE!!!!!!!!!!!!!!
-    // ******************************************************
-    std::vector<const char*> argv(startupParameters_.size() + 1);
-    
-    int argCounter = 0;
-    argvStrings[argCounter] = "dummy.exe";
-    argv[argCounter] = argvStrings[argCounter].c_str();
-    
-    argCounter++;
-    
-    std::string cmdLine = "";
-    for ( StartupParameters::const_iterator it = startupParameters_.begin(); 
-          it != startupParameters_.end(); 
-          it++)
-    {
-      std::stringstream argSs;
-
-      argSs << "--" << std::get<0>(*it);
-      if(std::get<1>(*it).length() > 0)
-        argSs << "=" << std::get<1>(*it);
-      
-      argvStrings[argCounter] = argSs.str();
-      cmdLine = cmdLine + " " + argvStrings[argCounter];
-      std::cout << cmdLine << std::endl;
-      argv[argCounter] = argvStrings[argCounter].c_str();
-      argCounter++;
-    }
-
-
-    std::cout << "simulated cmdLine = \"" << cmdLine.c_str() << "\"\n";
-
-    try
-    {
-      boost::program_options::store(
-        boost::program_options::command_line_parser(argCounter, argv.data()).
-          options(options).allow_unregistered().run(), parameters);
-      boost::program_options::notify(parameters);
-    }
-    catch (boost::program_options::error& e)
-    {
-      std::cerr << "Error while parsing the command-line arguments: " <<
-        e.what() << std::endl;    
-    }
-  }
-}
--- a/Applications/Wasm/StartupParametersBuilder.h	Wed Apr 29 20:43:09 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2020 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include <boost/program_options.hpp>
-#include <tuple>
-
-#if ORTHANC_ENABLE_SDL == 1
-#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 0
-#endif
-
-namespace OrthancStone
-{
-  // This class is used to generate boost program options from a dico.
-  // In a Wasm context, startup options are passed as URI arguments that
-  // are then passed to this class as a dico.
-  // This class regenerates a fake command-line and parses it to produce
-  // the same output as if the app was started at command-line.
-  class StartupParametersBuilder
-  {
-    typedef std::list<std::tuple<std::string, std::string>> StartupParameters;
-    StartupParameters startupParameters_;
-
-  public:
-
-    void Clear();
-    // Please note that if a parameter is a flag-style one, the value that 
-    // is passed should be an empty string
-    void SetStartupParameter(const char* name, const char* value);
-    void GetStartupParameters(
-      boost::program_options::variables_map& parameters_, 
-      const boost::program_options::options_description& options);
-  };
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Commands/BaseCommands.yml	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,10 @@
+SelectTool:
+  target: Application
+  toolName: string
+  comment: Selects the current application tool
+DownloadDicom:
+  target: SliceViewerWidget
+  comment: Downloads the slice currently displayed in the SliceViewerWidget
+Export:
+  target: IWidget
+  comment: Export the content of the widget
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/GuiAdapter.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,1142 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "GuiAdapter.h"
+
+#if ORTHANC_ENABLE_OPENGL == 1
+#  include "../../Framework/OpenGL/OpenGLIncludes.h"
+#endif
+
+#if ORTHANC_ENABLE_SDL == 1
+#  include <SDL_video.h>
+#  include <SDL_render.h>
+#  include <SDL.h>
+#endif
+
+#if ORTHANC_ENABLE_THREADS == 1
+#  include "../../Framework/Deprecated/Messages/LockingEmitter.h"
+#endif
+
+#include <Core/Compatibility.h>
+
+namespace OrthancStone
+{
+  std::ostream& operator<<(
+    std::ostream& os, const GuiAdapterKeyboardEvent& event)
+  {
+    os << "sym: " << event.sym << " (" << (int)(event.sym[0]) << ") ctrl: " << event.ctrlKey << ", " <<
+      "shift: " << event.shiftKey << ", " <<
+      "alt: " << event.altKey;
+    return os;
+  }
+
+  std::ostream& operator<<(
+    std::ostream& os, const GuiAdapterMouseEvent& event)
+  {
+    os << "targetX: " << event.targetX << " targetY: " << event.targetY << " button: " << event.button
+      << "ctrlKey: " << event.ctrlKey << "shiftKey: " << event.shiftKey << "altKey: " << event.altKey;
+      
+    return os;
+  }
+
+#if ORTHANC_ENABLE_WASM == 1
+  void GuiAdapter::Run(GuiAdapterRunFunc /*func*/, void* /*cookie*/)
+  {
+  }
+
+  void ConvertFromPlatform(
+    GuiAdapterUiEvent& dest,
+    int                      eventType,
+    const EmscriptenUiEvent& src)
+  {
+    // no data for now
+  }
+
+  void ConvertFromPlatform(
+    GuiAdapterMouseEvent& dest,
+    int                         eventType,
+    const EmscriptenMouseEvent& src)
+  {
+    memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
+    switch (eventType)
+    {
+    case EMSCRIPTEN_EVENT_CLICK:
+      LOG(ERROR) << "Emscripten EMSCRIPTEN_EVENT_CLICK is not supported";
+      ORTHANC_ASSERT(false, "Not supported");
+      break;
+    case EMSCRIPTEN_EVENT_MOUSEDOWN:
+      dest.type = GUIADAPTER_EVENT_MOUSEDOWN;
+      break;
+    case EMSCRIPTEN_EVENT_DBLCLICK:
+      dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK;
+      break;
+    case EMSCRIPTEN_EVENT_MOUSEMOVE:
+      dest.type = GUIADAPTER_EVENT_MOUSEMOVE;
+      break;
+    case EMSCRIPTEN_EVENT_MOUSEUP:
+      dest.type = GUIADAPTER_EVENT_MOUSEUP;
+      break;
+    case EMSCRIPTEN_EVENT_WHEEL:
+      dest.type = GUIADAPTER_EVENT_WHEEL;
+      break;
+
+    default:
+      LOG(ERROR) << "Emscripten event: " << eventType << " is not supported";
+      ORTHANC_ASSERT(false, "Not supported");
+    }
+    //dest.timestamp = src.timestamp;
+    //dest.screenX = src.screenX;
+    //dest.screenY = src.screenY;
+    //dest.clientX = src.clientX;
+    //dest.clientY = src.clientY;
+    dest.ctrlKey = src.ctrlKey;
+    dest.shiftKey = src.shiftKey;
+    dest.altKey = src.altKey;
+    //dest.metaKey = src.metaKey;
+    dest.button = src.button;
+    //dest.buttons = src.buttons;
+    //dest.movementX = src.movementX;
+    //dest.movementY = src.movementY;
+    dest.targetX = src.targetX;
+    dest.targetY = src.targetY;
+    //dest.canvasX = src.canvasX;
+    //dest.canvasY = src.canvasY;
+    //dest.padding = src.padding;
+  }
+
+  void ConvertFromPlatform( GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src)
+  {
+    ConvertFromPlatform(dest.mouse, eventType, src.mouse);
+    dest.deltaX = src.deltaX;
+    dest.deltaY = src.deltaY;
+    switch (src.deltaMode)
+    {
+    case DOM_DELTA_PIXEL:
+      dest.deltaMode = GUIADAPTER_DELTA_PIXEL;
+      break;
+    case DOM_DELTA_LINE:
+      dest.deltaMode = GUIADAPTER_DELTA_LINE;
+      break;
+    case DOM_DELTA_PAGE:
+      dest.deltaMode = GUIADAPTER_DELTA_PAGE;
+      break;
+    default:
+      ORTHANC_ASSERT(false, "Unknown deltaMode: " << src.deltaMode <<
+        " in wheel event...");
+    }
+    dest.deltaMode = src.deltaMode;
+  }
+
+  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src)
+  {
+    dest.sym[0] = src.key[0];
+    dest.sym[1] = 0;
+    dest.ctrlKey = src.ctrlKey;
+    dest.shiftKey = src.shiftKey;
+    dest.altKey = src.altKey;
+  }
+
+  template<typename GenericFunc>
+  struct FuncAdapterPayload
+  {
+    std::string canvasCssSelector;
+    void* userData;
+    GenericFunc callback;
+  };
+
+  template<typename GenericFunc,
+    typename GuiAdapterEvent,
+    typename EmscriptenEvent>
+    EM_BOOL OnEventAdapterFunc(
+      int eventType, const EmscriptenEvent* emEvent, void* userData)
+  {
+    // userData is OnMouseWheelFuncAdapterPayload
+    FuncAdapterPayload<GenericFunc>* payload =
+      reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
+    // LOG(INFO) << "OnEventAdapterFunc";
+    // LOG(INFO) << "------------------";
+    // LOG(INFO) << "eventType: " << eventType << " wheelEvent: " << 
+    //   (int)wheelEvent << " userData: " << userData << 
+    //   " payload->userData: " << payload->userData;
+
+    GuiAdapterEvent guiEvent;
+    ConvertFromPlatform(guiEvent, eventType, *emEvent);
+    bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData);
+    return static_cast<EM_BOOL>(ret);
+  }
+
+  template<typename GenericFunc,
+    typename GuiAdapterEvent,
+    typename EmscriptenEvent>
+    EM_BOOL OnEventAdapterFunc2(
+      int /*eventType*/, const EmscriptenEvent* wheelEvent, void* userData)
+  {
+    // userData is OnMouseWheelFuncAdapterPayload
+    FuncAdapterPayload<GenericFunc>* payload =
+      reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
+
+    GuiAdapterEvent guiEvent;
+    ConvertFromPlatform(guiEvent, *wheelEvent);
+    bool ret = (*(payload->callback))(payload->canvasCssSelector, &guiEvent, payload->userData);
+    return static_cast<EM_BOOL>(ret);
+  }
+
+  template<typename GenericFunc>
+  EM_BOOL OnEventAdapterFunc3(
+    double time, void* userData)
+  {
+    // userData is OnMouseWheelFuncAdapterPayload
+    FuncAdapterPayload<GenericFunc>* payload =
+      reinterpret_cast<FuncAdapterPayload<GenericFunc>*>(userData);
+    //std::unique_ptr< FuncAdapterPayload<GenericFunc> > deleter(payload);
+    bool ret = (*(payload->callback))(time, payload->userData);
+    return static_cast<EM_BOOL>(ret);
+  }
+
+  /*
+  
+  Explanation
+  ===========
+
+  - in "older" Emscripten, where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR doesn't exist or is set to 0,
+    the following strings need to be used to register events:
+    - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs 
+      to be "mycanvas"
+    - for the window (for key events), the string needs to be "#window"
+  - in newer Emscripten where DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR==1 (or maybe is not there anymore, in the
+    future as of 2020-04-20)
+    - for canvas, the canvas DOM id. In case of <canvas id="mycanvas1" width='640' ...></canvas>", the string needs
+      to be "#mycanvas"  (notice the "number sign", aka "hash", NOT AKA "sharp", as can be read on https://en.wikipedia.org/wiki/Number_sign)
+    - for the window (for key events), the string needs to be EMSCRIPTEN_EVENT_TARGET_WINDOW. I do not mean 
+      "EMSCRIPTEN_EVENT_TARGET_WINDOW", but the #define EMSCRIPTEN_EVENT_TARGET_WINDOW         ((const char*)2) that
+      can be found in emscripten/html5.h
+
+  The code below converts the input canvasId (as in the old emscripten) to the emscripten-compliant one, with the
+  following compile condition : #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1
+
+  If the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR build parameter disappears, you might want to refactor this code
+  or continue to pass the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR compile macro (which is different from the CMake
+  variable)     
+
+  What we are doing below:
+  - in older Emscripten, the registration functions will receive "mycanvas" and "#window" and the callbacks will receive 
+    the same std::string in their payload ("mycanvas" and "#window")
+
+  - in newer Emscripten, the registration functions will receive "#mycanvas" and EMSCRIPTEN_EVENT_TARGET_WINDOW, but 
+    the callbacks will receive "#mycanvas" and "#window" (since it is not possible to store the EMSCRIPTEN_EVENT_TARGET_WINDOW
+    magic value in an std::string, while we still want the callback to be able to change its behavior according to the
+    target element.
+  
+  */
+
+  void convertElementTarget(const char*& outCanvasCssSelectorSz, std::string& outCanvasCssSelector, const std::string& canvasId)
+  {
+    // only "#window" can start with a #
+    if (canvasId[0] == '#')
+    {
+      ORTHANC_ASSERT(canvasId == "#window");
+    }
+#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1
+    if (canvasId == "#window")
+    {
+      // we store this in the payload so that the callback can 
+      outCanvasCssSelector = "#window";
+      outCanvasCssSelectorSz = EMSCRIPTEN_EVENT_TARGET_WINDOW;
+    }
+    else
+    {
+      outCanvasCssSelector = "#" + canvasId;
+      outCanvasCssSelectorSz = outCanvasCssSelector.c_str();
+    }
+#else
+    if (canvasId == "#window")
+    {
+      // we store this in the payload so that the callback can 
+      outCanvasCssSelector = "#window";
+      outCanvasCssSelectorSz = outCanvasCssSelector.c_str();;
+    }
+    else
+    {
+      outCanvasCssSelector = canvasId;
+      outCanvasCssSelectorSz = outCanvasCssSelector.c_str();;
+    }
+#endif
+  }
+
+  // resize: (const char* target, void* userData, EM_BOOL useCapture, em_ui_callback_func callback)
+  template<
+    typename GenericFunc,
+    typename GuiAdapterEvent,
+    typename EmscriptenEvent,
+    typename EmscriptenSetCallbackFunc>
+    static void SetCallback(
+      EmscriptenSetCallbackFunc emFunc,
+      std::string canvasId, void* userData, bool capture, GenericFunc func)
+  {
+    std::string canvasCssSelector;
+    const char* canvasCssSelectorSz = NULL;
+    convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId);
+
+    // TODO: write RemoveCallback with an int id that gets returned from here
+
+    // create userdata payload
+    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>());
+    payload->canvasCssSelector = canvasCssSelector;
+    payload->callback = func;
+    payload->userData = userData;
+    void* userDataRaw = reinterpret_cast<void*>(payload.release());
+
+    // call the registration function
+    (*emFunc)(
+      canvasCssSelectorSz,
+      userDataRaw,
+      static_cast<EM_BOOL>(capture),
+      &OnEventAdapterFunc<GenericFunc, GuiAdapterEvent, EmscriptenEvent>,
+      EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD);
+  }
+
+  template<
+    typename GenericFunc,
+    typename GuiAdapterEvent,
+    typename EmscriptenEvent,
+    typename EmscriptenSetCallbackFunc>
+    static void SetCallback2(
+      EmscriptenSetCallbackFunc emFunc,
+      std::string canvasId, void* userData, bool capture, GenericFunc func)
+  {
+    std::string canvasCssSelector;
+    const char* canvasCssSelectorSz = NULL;
+    convertElementTarget(canvasCssSelectorSz, canvasCssSelector, canvasId);
+
+    // TODO: write RemoveCallback with an int id that gets returned from here
+
+    // create userdata payload
+    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(new FuncAdapterPayload<GenericFunc>());
+    payload->canvasCssSelector = canvasCssSelector;
+    payload->callback = func;
+    payload->userData = userData;
+    void* userDataRaw = reinterpret_cast<void*>(payload.release());
+
+    // call the registration function
+    (*emFunc)(
+      canvasCssSelectorSz,
+      userDataRaw,
+      static_cast<EM_BOOL>(capture),
+      &OnEventAdapterFunc2<GenericFunc, GuiAdapterEvent, EmscriptenEvent>,
+      EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD);
+  }
+
+  template<
+    typename GenericFunc,
+    typename EmscriptenSetCallbackFunc>
+    static void SetAnimationFrameCallback(
+      EmscriptenSetCallbackFunc emFunc,
+      void* userData, GenericFunc func)
+  {
+    std::unique_ptr<FuncAdapterPayload<GenericFunc> > payload(
+      new FuncAdapterPayload<GenericFunc>()
+    );
+    payload->canvasCssSelector = "UNDEFINED";
+    payload->callback = func;
+    payload->userData = userData;
+    void* userDataRaw = reinterpret_cast<void*>(payload.release());
+    (*emFunc)(
+      &OnEventAdapterFunc3<GenericFunc>,
+      userDataRaw);
+  }
+
+  void GuiAdapter::SetWheelCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseWheelFunc func)
+  {
+    SetCallback<OnMouseWheelFunc, GuiAdapterWheelEvent, EmscriptenWheelEvent>(
+      &emscripten_set_wheel_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+  
+  void GuiAdapter::SetMouseDblClickCallback(
+      std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
+  {
+    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
+      &emscripten_set_dblclick_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+
+  void GuiAdapter::SetMouseDownCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
+  {
+    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
+      &emscripten_set_mousedown_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+  void GuiAdapter::SetMouseMoveCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
+  {
+    // LOG(INFO) << "SetMouseMoveCallback -- " << "supplied userData: " << 
+    //   userData;
+
+    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
+      &emscripten_set_mousemove_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+  void GuiAdapter::SetMouseUpCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
+  {
+    SetCallback<OnMouseEventFunc, GuiAdapterMouseEvent, EmscriptenMouseEvent>(
+      &emscripten_set_mouseup_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+  void GuiAdapter::SetKeyDownCallback(
+    std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
+  {
+    SetCallback2<OnKeyDownFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>(
+      &emscripten_set_keydown_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+  void GuiAdapter::SetKeyUpCallback(
+    std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
+  {
+    SetCallback2<OnKeyUpFunc, GuiAdapterKeyboardEvent, EmscriptenKeyboardEvent>(
+      &emscripten_set_keyup_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+
+#if 0
+  // useless under Wasm where canvas resize is handled automatically
+  void GuiAdapter::SetResizeCallback(
+    std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
+  {
+    SetCallback<OnWindowResizeFunc, GuiAdapterUiEvent, EmscriptenUiEvent>(
+      &emscripten_set_resize_callback_on_thread,
+      canvasId,
+      userData,
+      capture,
+      func);
+  }
+#endif
+
+  void GuiAdapter::RequestAnimationFrame(
+    OnAnimationFrameFunc func, void* userData)
+  {
+    SetAnimationFrameCallback<OnAnimationFrameFunc>(
+      &emscripten_request_animation_frame_loop,
+      userData,
+      func);
+  }
+
+#if 0
+  void GuiAdapter::SetKeyDownCallback(
+    std::string canvasId, void* userData, bool capture, OnKeyDownFunc func)
+  {
+    emscripten_set_keydown_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
+  }
+  void GuiAdapter::SetKeyUpCallback(
+    std::string canvasId, void* userData, bool capture, OnKeyUpFunc func)
+  {
+    emscripten_set_keyup_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
+  }
+
+  // handled from within WebAssemblyViewport
+  //void GuiAdapter::SetResizeCallback(std::string canvasId, void* userData, bool capture, OnWindowResizeFunc func)
+  //{
+  //  emscripten_set_resize_callback(canvasId.c_str(), userData, static_cast<EM_BOOL>(capture), func);
+  //}
+
+  void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
+  {
+    emscripten_request_animation_frame_loop(func, userData);
+  }
+#endif
+
+
+#else
+
+  // SDL ONLY
+  void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source)
+  {
+    memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
+    switch (source.type)
+    {
+    case SDL_MOUSEBUTTONDOWN:
+      if (source.button.clicks == 1) {
+        dest.type = GUIADAPTER_EVENT_MOUSEDOWN;
+      } else if (source.button.clicks == 2) {
+        dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK;
+      } else {
+        dest.type = GUIADAPTER_EVENT_MOUSEDBLCLICK;
+        LOG(WARNING) << "Multiple-click ignored.";
+      }
+      break;
+    case SDL_MOUSEMOTION:
+      dest.type = GUIADAPTER_EVENT_MOUSEMOVE;
+      break;
+    case SDL_MOUSEBUTTONUP:
+      dest.type = GUIADAPTER_EVENT_MOUSEUP;
+      break;
+    case SDL_MOUSEWHEEL:
+      dest.type = GUIADAPTER_EVENT_WHEEL;
+      break;
+    default:
+      LOG(ERROR) << "SDL event: " << source.type << " is not supported";
+      ORTHANC_ASSERT(false, "Not supported");
+    }
+    //dest.timestamp = src.timestamp;
+    //dest.screenX = src.screenX;
+    //dest.screenY = src.screenY;
+    //dest.clientX = src.clientX;
+    //dest.clientY = src.clientY;
+    dest.ctrlKey = ctrlPressed;
+    dest.shiftKey = shiftPressed;
+    dest.altKey = altPressed;
+    //dest.metaKey = src.metaKey;
+    switch (source.button.button)
+    {
+    case SDL_BUTTON_MIDDLE:
+      dest.button =GUIADAPTER_MOUSEBUTTON_MIDDLE;
+      break;
+
+    case SDL_BUTTON_RIGHT:
+      dest.button = GUIADAPTER_MOUSEBUTTON_RIGHT;
+      break;
+
+    case SDL_BUTTON_LEFT:
+      dest.button = GUIADAPTER_MOUSEBUTTON_LEFT;
+      break;
+
+    default:
+      break;
+    }
+    //dest.buttons = src.buttons;
+    //dest.movementX = src.movementX;
+    //dest.movementY = src.movementY;
+    dest.targetX = source.button.x;
+    dest.targetY = source.button.y;
+    //dest.canvasX = src.canvasX;
+    //dest.canvasY = src.canvasY;
+    //dest.padding = src.padding;
+  }
+
+  void ConvertFromPlatform(
+    GuiAdapterWheelEvent& dest,
+    bool ctrlPressed, bool shiftPressed, bool altPressed,
+    const SDL_Event& source)
+  {
+    ConvertFromPlatform(dest.mouse, ctrlPressed, shiftPressed, altPressed, source);
+    dest.deltaX = source.wheel.x;
+    dest.deltaY = source.wheel.y;
+  }
+
+  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& src)
+  {
+    memset(&dest, 0, sizeof(GuiAdapterMouseEvent));
+    switch (src.type)
+    {
+    case SDL_KEYDOWN:
+      dest.type = GUIADAPTER_EVENT_KEYDOWN;
+      break;
+    case SDL_KEYUP:
+      dest.type = GUIADAPTER_EVENT_KEYUP;
+      break;
+    default:
+      LOG(ERROR) << "SDL event: " << src.type << " is not supported";
+      ORTHANC_ASSERT(false, "Not supported");
+    }
+    dest.sym[0] = src.key.keysym.sym;
+    dest.sym[1] = 0;
+
+    if (src.key.keysym.mod & KMOD_CTRL)
+      dest.ctrlKey = true;
+    else
+      dest.ctrlKey = false;
+
+    if (src.key.keysym.mod & KMOD_SHIFT)
+      dest.shiftKey = true;
+    else
+      dest.shiftKey = false;
+
+    if (src.key.keysym.mod & KMOD_ALT)
+      dest.altKey = true;
+    else
+      dest.altKey = false;
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetSdlResizeCallback(
+    std::string canvasId, void* userData, bool capture, OnSdlWindowResizeFunc func)
+  {
+    resizeHandlers_.push_back(EventHandlerData<OnSdlWindowResizeFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetMouseDownCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
+  {
+    mouseDownHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetMouseDblClickCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc func)
+  {
+    mouseDblCickHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetMouseMoveCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc  func)
+  {
+    mouseMoveHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetMouseUpCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseEventFunc  func)
+  {
+    mouseUpHandlers_.push_back(EventHandlerData<OnMouseEventFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetWheelCallback(
+    std::string canvasId, void* userData, bool capture, OnMouseWheelFunc  func)
+  {
+    mouseWheelHandlers_.push_back(EventHandlerData<OnMouseWheelFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetKeyDownCallback(
+    std::string canvasId, void* userData, bool capture, OnKeyDownFunc   func)
+  {
+    keyDownHandlers_.push_back(EventHandlerData<OnKeyDownFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetKeyUpCallback(
+    std::string canvasId, void* userData, bool capture, OnKeyUpFunc    func)
+  {
+    keyUpHandlers_.push_back(EventHandlerData<OnKeyUpFunc>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::SetGenericSdlEventCallback(
+    std::string canvasId, void* userData, bool capture, OnSdlEventCallback func)
+  {
+    sdlEventHandlers_.push_back(EventHandlerData<OnSdlEventCallback>(canvasId, func, userData));
+  }
+
+  // SDL ONLY
+  void GuiAdapter::OnAnimationFrame()
+  {
+    std::vector<size_t> disabledAnimationHandlers;
+    for (size_t i = 0; i < animationFrameHandlers_.size(); i++)
+    {
+      // TODO: fix time 
+      bool goOn = (*(animationFrameHandlers_[i].first))(0, animationFrameHandlers_[i].second);
+
+      // If the function returns false, we need to emulate what happens in Web 
+      // and remove the function from the handlers...
+      if (!goOn)
+        disabledAnimationHandlers.push_back(i);
+    }
+    for (size_t i = 0; i < disabledAnimationHandlers.size(); i++)
+    {
+      ORTHANC_ASSERT(animationFrameHandlers_.begin() + disabledAnimationHandlers[i] < animationFrameHandlers_.end());
+      animationFrameHandlers_.erase(animationFrameHandlers_.begin() + disabledAnimationHandlers[i]);
+    }
+  }
+
+  // SDL ONLY
+  void GuiAdapter::OnResize(unsigned int width, unsigned int height)
+  {
+    for (size_t i = 0; i < resizeHandlers_.size(); i++)
+    {
+      (*(resizeHandlers_[i].func))(
+        resizeHandlers_[i].canvasName, NULL, width, height, resizeHandlers_[i].userData);
+    }
+  }
+
+
+
+  void GuiAdapter::OnSdlGenericEvent(const SDL_Event& sdlEvent)
+  {
+    // Events related to a window are only sent to the related canvas
+    // User events are sent to everyone (we can't filter them here)
+    
+    /*
+    SDL_WindowEvent    SDL_WINDOWEVENT
+    SDL_KeyboardEvent     SDL_KEYDOWN
+                          SDL_KEYUP
+    SDL_TextEditingEvent  SDL_TEXTEDITING
+    SDL_TextInputEvent    SDL_TEXTINPUT
+    SDL_MouseMotionEvent  SDL_MOUSEMOTION
+    SDL_MouseButtonEvent  SDL_MOUSEBUTTONDOWN 
+                          SDL_MOUSEBUTTONUP
+    SDL_MouseWheelEvent   SDL_MOUSEWHEEL
+    SDL_UserEvent         SDL_USEREVENT through ::SDL_LASTEVENT-1
+    */
+
+    // if this string is left empty, it means the message will be sent to
+    // all widgets.
+    // otherwise, it contains the originating message window title
+
+    std::string windowTitle;
+    uint32_t windowId = 0;
+
+    if (sdlEvent.type == SDL_WINDOWEVENT)
+      windowId = sdlEvent.window.windowID;
+    else if (sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP)
+      windowId = sdlEvent.key.windowID;
+    else if (sdlEvent.type == SDL_TEXTEDITING)
+      windowId = sdlEvent.edit.windowID;
+    else if (sdlEvent.type == SDL_TEXTINPUT)
+      windowId = sdlEvent.text.windowID;
+    else if (sdlEvent.type == SDL_MOUSEMOTION)
+      windowId = sdlEvent.motion.windowID;
+    else if (sdlEvent.type == SDL_MOUSEBUTTONDOWN || sdlEvent.type == SDL_MOUSEBUTTONUP)
+      windowId = sdlEvent.button.windowID;
+    else if (sdlEvent.type == SDL_MOUSEWHEEL)
+      windowId = sdlEvent.wheel.windowID;
+    else if (sdlEvent.type >= SDL_USEREVENT && sdlEvent.type <= (SDL_LASTEVENT-1))
+      windowId = sdlEvent.user.windowID;
+
+    if (windowId != 0)
+    {
+      SDL_Window* sdlWindow = SDL_GetWindowFromID(windowId);
+      ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowId << "\" is not a valid SDL window ID!");
+      const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
+      ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowId << "\" has a NULL window title!");
+      windowTitle = windowTitleSz;
+      ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowId << "\" has an empty window title!");
+    }
+
+    for (size_t i = 0; i < sdlEventHandlers_.size(); i++)
+    {
+      // normally, the handlers return a bool indicating whether they
+      // have handled the event or not, but we don't really care about this
+      std::string& canvasName = sdlEventHandlers_[i].canvasName;
+      
+      bool sendEvent = true;
+
+      if (windowTitle != "" && (canvasName != windowTitle))
+        sendEvent = false;
+
+      if (sendEvent)
+      {
+        OnSdlEventCallback func = sdlEventHandlers_[i].func;
+        (*func)(canvasName, sdlEvent, sdlEventHandlers_[i].userData);
+      }
+    }
+  }
+
+  // SDL ONLY
+  void GuiAdapter::OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event)
+  {
+    // the SDL window name IS the canvas name ("canvas" is used because this lib
+    // is designed for Wasm
+    SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID);
+    ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!");
+
+    const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
+    ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!");
+
+    std::string windowTitle(windowTitleSz);
+    ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!");
+
+    switch (event.mouse.type)
+    {
+    case GUIADAPTER_EVENT_WHEEL:
+      for (size_t i = 0; i < mouseWheelHandlers_.size(); i++)
+      {
+        if (mouseWheelHandlers_[i].canvasName == windowTitle)
+          (*(mouseWheelHandlers_[i].func))(windowTitle, &event, mouseWheelHandlers_[i].userData);
+      }
+      break;
+    default:
+      ORTHANC_ASSERT(false, "Wrong event.type: " << event.mouse.type << " in GuiAdapter::OnMouseWheelEvent(...)");
+      break;
+    }
+  }
+
+
+  void GuiAdapter::OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event)
+  {
+    // only one-letter (ascii) keyboard events supported for now
+    ORTHANC_ASSERT(event.sym[0] != 0);
+    ORTHANC_ASSERT(event.sym[1] == 0);
+
+    SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID);
+    ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!");
+
+    const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
+    ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!");
+
+    std::string windowTitle(windowTitleSz);
+    ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!");
+
+    switch (event.type)
+    {
+    case GUIADAPTER_EVENT_KEYDOWN:
+      for (size_t i = 0; i < keyDownHandlers_.size(); i++)
+      {
+        (*(keyDownHandlers_[i].func))(windowTitle, &event, keyDownHandlers_[i].userData);
+      }
+      break;
+    case GUIADAPTER_EVENT_KEYUP:
+      for (size_t i = 0; i < keyUpHandlers_.size(); i++)
+      {
+        (*(keyUpHandlers_[i].func))(windowTitle, &event, keyUpHandlers_[i].userData);
+      }
+      break;
+    default:
+      ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnKeyboardEvent(...)");
+      break;
+    }
+  }
+
+  // SDL ONLY
+  void GuiAdapter::OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event)
+  {
+    if (windowID == 0)
+    {
+      LOG(WARNING) << "GuiAdapter::OnMouseEvent -- windowID == 0 and event won't be routed!";
+    }
+    else
+    {
+      // the SDL window name IS the canvas name ("canvas" is used because this lib
+      // is designed for Wasm
+      SDL_Window* sdlWindow = SDL_GetWindowFromID(windowID);
+
+      ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << windowID << "\" is not a valid SDL window ID!");
+
+      const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
+      ORTHANC_ASSERT(windowTitleSz != NULL, "Window ID \"" << windowID << "\" has a NULL window title!");
+
+      std::string windowTitle(windowTitleSz);
+      ORTHANC_ASSERT(windowTitle != "", "Window ID \"" << windowID << "\" has an empty window title!");
+
+      switch (event.type)
+      {
+      case GUIADAPTER_EVENT_MOUSEDOWN:
+        for (size_t i = 0; i < mouseDownHandlers_.size(); i++)
+        {
+          if (mouseDownHandlers_[i].canvasName == windowTitle)
+            (*(mouseDownHandlers_[i].func))(windowTitle, &event, mouseDownHandlers_[i].userData);
+        }
+        break;
+      case GUIADAPTER_EVENT_MOUSEDBLCLICK:
+        for (size_t i = 0; i < mouseDblCickHandlers_.size(); i++)
+        {
+          if (mouseDblCickHandlers_[i].canvasName == windowTitle)
+            (*(mouseDblCickHandlers_[i].func))(windowTitle, &event, mouseDblCickHandlers_[i].userData);
+        }
+        break;
+      case GUIADAPTER_EVENT_MOUSEMOVE:
+        for (size_t i = 0; i < mouseMoveHandlers_.size(); i++)
+        {
+          if (mouseMoveHandlers_[i].canvasName == windowTitle)
+            (*(mouseMoveHandlers_[i].func))(windowTitle, &event, mouseMoveHandlers_[i].userData);
+        }
+        break;
+      case GUIADAPTER_EVENT_MOUSEUP:
+        for (size_t i = 0; i < mouseUpHandlers_.size(); i++)
+        {
+          if (mouseUpHandlers_[i].canvasName == windowTitle)
+            (*(mouseUpHandlers_[i].func))(windowTitle, &event, mouseUpHandlers_[i].userData);
+        }
+        break;
+      default:
+        ORTHANC_ASSERT(false, "Wrong event.type: " << event.type << " in GuiAdapter::OnMouseEvent(...)");
+        break;
+      }
+    }
+  }
+
+
+  // extern void Debug_SetContextToBeKilled(std::string title);
+  // extern void Debug_SetContextToBeRestored(std::string title);
+
+  // SDL ONLY
+  void GuiAdapter::RequestAnimationFrame(OnAnimationFrameFunc func, void* userData)
+  {
+    animationFrameHandlers_.push_back(std::make_pair(func, userData));
+  }
+
+# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__)   /* OpenGL debug is not available on OS X */
+
+  // SDL ONLY
+  static void GLAPIENTRY
+    OpenGLMessageCallback(GLenum source,
+      GLenum type,
+      GLuint id,
+      GLenum severity,
+      GLsizei length,
+      const GLchar * message,
+      const void* userParam)
+  {
+    if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
+    {
+      fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
+        (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
+        type, severity, message);
+    }
+  }
+# endif
+
+#if 0
+  // TODO: remove this when generic sdl event handlers are implemented in 
+  // the DoseView
+  // SDL ONLY
+  bool GuiAdapter::IsSdlViewPortRefreshEvent(const SDL_Event& event) const
+  {
+    SDL_Window* sdlWindow = SDL_GetWindowFromID(event.window.windowID);
+
+    ORTHANC_ASSERT(sdlWindow != NULL, "Window ID \"" << event.window.windowID << "\" is not a valid SDL window ID!");
+
+    const char* windowTitleSz = SDL_GetWindowTitle(sdlWindow);
+
+    // now we need to find the DoseView from from the canvas name!
+    // (and retrieve the SdlViewport)
+    boost::shared_ptr<IGuiAdapterWidget> foundWidget;
+    VisitWidgets([&foundWidget, windowTitleSz](auto widget)
+    {
+      if (widget->GetCanvasIdentifier() == std::string(windowTitleSz))
+        foundWidget = widget;
+    });
+    ORTHANC_ASSERT(foundWidget, "The window named: \"" << windowTitleSz << "\" was not found in the registered widgets!");
+    return foundWidget->GetSdlViewport().IsRefreshEvent(event);
+  }
+#endif
+
+  // SDL ONLY
+  void GuiAdapter::Run(GuiAdapterRunFunc func, void* cookie)
+  {
+#if 1
+    // TODO: MAKE THIS DYNAMIC !!! See SdlOpenGLViewport vs Cairo in ViewportWrapper
+# if ORTHANC_ENABLE_OPENGL == 1 && !defined(__APPLE__)
+    glEnable(GL_DEBUG_OUTPUT);
+    glDebugMessageCallback(OpenGLMessageCallback, 0);
+# endif
+#endif
+
+    // Uint32 SDL_GetWindowID(SDL_Window* window)
+    // SDL_Window* SDL_GetWindowFromID(Uint32 id)   // may return NULL
+
+    bool stop = false;
+    while (!stop)
+    {
+      {
+        // TODO: lock all viewports here! (use a scoped object)
+        if(func != NULL)
+          (*func)(cookie);
+        OnAnimationFrame(); // in SDL we must call it
+      }
+
+      while (!stop)
+      {
+        std::vector<SDL_Event> sdlEvents;
+        std::map<Uint32,SDL_Event> userEventsMap;
+        
+        SDL_Event sdlEvent;
+
+        // FIRST: collect all pending events
+        while (SDL_PollEvent(&sdlEvent) != 0)
+        {
+          if ( (sdlEvent.type >= SDL_USEREVENT) && 
+               (sdlEvent.type <= SDL_USEREVENT) )
+          {
+            // we don't want to have multiple events with the same event.type
+            userEventsMap[sdlEvent.type] = sdlEvent;
+          }
+          else
+          {
+            sdlEvents.push_back(sdlEvent);
+          }
+        }
+
+        // SECOND: collect all user events
+        for (std::map<Uint32,SDL_Event>::const_iterator it = userEventsMap.begin(); it != userEventsMap.end(); ++it)
+          sdlEvents.push_back(it->second);
+                
+        // now process the events
+        for (std::vector<SDL_Event>::const_iterator it = sdlEvents.begin(); it != sdlEvents.end(); ++it)
+        {
+          const SDL_Event& sdlEvent = *it;
+          // TODO: lock all viewports here! (use a scoped object)
+
+          if (sdlEvent.type == SDL_QUIT)
+          {
+            // TODO: call exit callbacks here
+            stop = true;
+            break;
+          }
+          else if ((sdlEvent.type == SDL_MOUSEMOTION) ||
+            (sdlEvent.type == SDL_MOUSEBUTTONDOWN) ||
+                   (sdlEvent.type == SDL_MOUSEBUTTONUP))
+          {
+            int scancodeCount = 0;
+            const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
+            bool ctrlPressed(false);
+            bool shiftPressed(false);
+            bool altPressed(false);
+
+            if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL])
+              ctrlPressed = true;
+            if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL])
+              ctrlPressed = true;
+            if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT])
+              shiftPressed = true;
+            if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT])
+              shiftPressed = true;
+            if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT])
+              altPressed = true;
+
+            GuiAdapterMouseEvent dest;
+            ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent);
+            OnMouseEvent(sdlEvent.window.windowID, dest);
+  #if 0
+            // for reference, how to create trackers
+            if (tracker)
+            {
+              PointerEvent e;
+              e.AddPosition(compositor.GetPixelCenterCoordinates(
+                sdlEvent.button.x, sdlEvent.button.y));
+              tracker->PointerMove(e);
+            }
+  #endif
+          }
+          else if (sdlEvent.type == SDL_MOUSEWHEEL)
+          {
+
+            int scancodeCount = 0;
+            const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
+            bool ctrlPressed(false);
+            bool shiftPressed(false);
+            bool altPressed(false);
+
+            if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL])
+              ctrlPressed = true;
+            if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL])
+              ctrlPressed = true;
+            if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT])
+              shiftPressed = true;
+            if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT])
+              shiftPressed = true;
+            if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT])
+              altPressed = true;
+
+            GuiAdapterWheelEvent dest;
+            ConvertFromPlatform(dest, ctrlPressed, shiftPressed, altPressed, sdlEvent);
+            OnMouseWheelEvent(sdlEvent.window.windowID, dest);
+
+            //KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
+
+            //int x, y;
+            //SDL_GetMouseState(&x, &y);
+
+            //if (sdlEvent.wheel.y > 0)
+            //{
+            //  locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers);
+            //}
+            //else if (sdlEvent.wheel.y < 0)
+            //{
+            //  locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
+            //}
+          }
+          else if (sdlEvent.type == SDL_WINDOWEVENT &&
+            (sdlEvent.window.event == SDL_WINDOWEVENT_RESIZED ||
+             sdlEvent.window.event == SDL_WINDOWEVENT_SIZE_CHANGED))
+          {
+  #if 0
+            tracker.reset();
+  #endif
+            OnResize(sdlEvent.window.data1, sdlEvent.window.data2);
+          }
+          else if (sdlEvent.type == SDL_KEYDOWN && sdlEvent.key.repeat == 0 /* Ignore key bounce */)
+          {
+            switch (sdlEvent.key.keysym.sym)
+            {
+            case SDLK_f:
+              // window.GetWindow().ToggleMaximize(); //TODO: move to particular handler
+              break;
+
+            // This commented out code was used to debug the context
+            // loss/restoring code (2019-08-10)
+            // case SDLK_k:
+            //   {
+            //     SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID);
+            //     std::string windowTitle(SDL_GetWindowTitle(window));
+            //     Debug_SetContextToBeKilled(windowTitle);
+            //   }
+            //   break;
+            // case SDLK_l:
+            //   {
+            //     SDL_Window* window = SDL_GetWindowFromID(sdlEvent.window.windowID);
+            //     std::string windowTitle(SDL_GetWindowTitle(window));
+            //     Debug_SetContextToBeRestored(windowTitle);
+            //   }
+            //   break;
+
+            case SDLK_q:
+              stop = true;
+              break;
+
+            default:
+              GuiAdapterKeyboardEvent dest;
+              ConvertFromPlatform(dest, sdlEvent);
+              OnKeyboardEvent(sdlEvent.window.windowID, dest);
+              break;
+            }
+          }
+        
+          OnSdlGenericEvent(sdlEvent);
+        }
+      }
+
+      SDL_Delay(1);
+    }
+  }
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/GuiAdapter.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,375 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+#pragma once
+
+#include <string>
+
+#if ORTHANC_ENABLE_WASM != 1
+# ifdef __EMSCRIPTEN__
+#   error __EMSCRIPTEN__ is defined and ORTHANC_ENABLE_WASM != 1
+# endif
+#endif
+
+#if ORTHANC_ENABLE_WASM == 1
+# ifndef __EMSCRIPTEN__
+#   error __EMSCRIPTEN__ is not defined and ORTHANC_ENABLE_WASM == 1
+# endif
+#endif
+
+#if ORTHANC_ENABLE_WASM == 1
+# include <emscripten/html5.h>
+#else
+# if ORTHANC_ENABLE_SDL == 1
+#   include <SDL.h>
+# endif
+#endif
+
+#include "../../Framework/StoneException.h"
+
+#if ORTHANC_ENABLE_THREADS == 1
+# include "../../Framework/Deprecated/Messages/LockingEmitter.h"
+#endif
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+namespace OrthancStone
+{
+#if ORTHANC_ENABLE_SDL == 1
+  class SdlViewport;
+#endif
+
+#if 0
+
+  /**
+  This interface is used to store the widgets that are controlled by the 
+  GuiAdapter and receive event callbacks.
+  The callbacks may possibly be downcast (using dynamic_cast, for safety) \
+  to the actual widget type
+  */
+  class IGuiAdapterWidget
+  {
+  public:
+    virtual ~IGuiAdapterWidget() {}
+    
+#if #if ORTHANC_ENABLE_SDL == 1
+    /**
+    Returns the SdlViewport that this widget contains. If the underlying 
+    viewport type is *not* SDL, then an error is returned.
+    */
+    virtual SdlViewport& GetSdlViewport() = 0;
+#endif
+  };
+
+#endif
+
+  enum GuiAdapterMouseButtonType
+  {
+    GUIADAPTER_MOUSEBUTTON_LEFT = 0,
+    GUIADAPTER_MOUSEBUTTON_MIDDLE = 1,
+    GUIADAPTER_MOUSEBUTTON_RIGHT = 2
+  };
+
+
+  enum GuiAdapterHidEventType
+  {
+    GUIADAPTER_EVENT_MOUSEDOWN      = 1973,
+    GUIADAPTER_EVENT_MOUSEMOVE      = 1974,
+    GUIADAPTER_EVENT_MOUSEDBLCLICK  = 1975,
+    GUIADAPTER_EVENT_MOUSEUP        = 1976,
+    GUIADAPTER_EVENT_WHEEL          = 1977,
+    GUIADAPTER_EVENT_KEYDOWN        = 1978,
+    GUIADAPTER_EVENT_KEYUP          = 1979,
+  };
+
+  const unsigned int GUIADAPTER_DELTA_PIXEL = 2973;
+  const unsigned int GUIADAPTER_DELTA_LINE  = 2974;
+  const unsigned int GUIADAPTER_DELTA_PAGE  = 2975;
+
+  struct GuiAdapterUiEvent;
+  struct GuiAdapterMouseEvent;
+  struct GuiAdapterWheelEvent;
+  struct GuiAdapterKeyboardEvent;
+
+#if 1
+  typedef bool (*OnMouseEventFunc)    (std::string canvasId, const GuiAdapterMouseEvent* mouseEvent, void* userData);
+  typedef bool (*OnMouseWheelFunc)    (std::string canvasId, const GuiAdapterWheelEvent* wheelEvent, void* userData);
+  typedef bool (*OnKeyDownFunc)       (std::string canvasId, const GuiAdapterKeyboardEvent*   keyEvent,   void* userData);
+  typedef bool (*OnKeyUpFunc)         (std::string canvasId, const GuiAdapterKeyboardEvent*   keyEvent,   void* userData);
+  typedef bool (*OnAnimationFrameFunc)(double time, void* userData);
+  
+#if ORTHANC_ENABLE_SDL == 1
+  typedef bool (*OnSdlEventCallback)  (std::string canvasId, const SDL_Event& sdlEvent, void* userData);
+
+  typedef bool (*OnSdlWindowResizeFunc)(std::string canvasId, 
+                                        const GuiAdapterUiEvent* uiEvent, 
+                                        unsigned int width, 
+                                        unsigned int height, 
+                                        void* userData);
+
+
+#endif
+
+#else
+
+#if ORTHANC_ENABLE_WASM == 1
+  typedef EM_BOOL (*OnMouseEventFunc)(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+  typedef EM_BOOL (*OnMouseWheelFunc)(int eventType, const EmscriptenWheelEvent* wheelEvent, void* userData);
+  typedef EM_BOOL (*OnKeyDownFunc)   (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
+  typedef EM_BOOL (*OnKeyUpFunc)     (int eventType, const EmscriptenKeyboardEvent* keyEvent, void* userData);
+
+  typedef EM_BOOL (*OnAnimationFrameFunc)(double time, void* userData);
+  typedef EM_BOOL (*OnWindowResizeFunc)(int eventType, const EmscriptenUiEvent* uiEvent, void* userData);
+#else
+  typedef bool    (*OnMouseEventFunc)(int eventType, const SDL_Event* mouseEvent, void* userData);
+  typedef bool    (*OnMouseWheelFunc)(int eventType, const SDL_Event* wheelEvent, void* userData);
+  typedef bool    (*OnKeyDownFunc)   (int eventType, const SDL_Event* keyEvent,   void* userData);
+  typedef bool    (*OnKeyUpFunc)     (int eventType, const SDL_Event* keyEvent,   void* userData);
+
+  typedef bool    (*OnAnimationFrameFunc)(double time, void* userData);
+  typedef bool    (*OnWindowResizeFunc)(int eventType, const GuiAdapterUiEvent* uiEvent, void* userData);
+#endif
+
+#endif
+  struct GuiAdapterMouseEvent
+  {
+    GuiAdapterHidEventType type;
+    //double                   timestamp;
+    //long                     screenX;
+    //long                     screenY;
+    //long                     clientX;
+    //long                     clientY;
+    bool                     ctrlKey;
+    bool                     shiftKey;
+    bool                     altKey;
+    //bool                     metaKey;
+    unsigned short           button;
+    //unsigned short           buttons;
+    //long                     movementX;
+    //long                     movementY;
+    long                     targetX;
+    long                     targetY;
+    // canvasX and canvasY are deprecated - there no longer exists a Module['canvas'] object, so canvasX/Y are no longer reported (register a listener on canvas directly to get canvas coordinates, or translate manually)
+    //long                     canvasX;
+    //long                     canvasY;
+    //long                     padding;
+
+  public:
+    GuiAdapterMouseEvent()
+      : ctrlKey(false),
+        shiftKey(false),
+        altKey(false)
+    {
+    }
+  };
+
+  struct GuiAdapterWheelEvent {
+    GuiAdapterMouseEvent mouse;
+    double deltaX;
+    double deltaY;
+    unsigned long deltaMode;
+  };
+
+  // we don't use any data now
+  struct GuiAdapterUiEvent {};
+
+  // EmscriptenKeyboardEvent
+  struct GuiAdapterKeyboardEvent
+  {
+    GuiAdapterHidEventType type;
+    char sym[32];
+    bool ctrlKey;
+    bool shiftKey;
+    bool altKey;
+  };
+
+  std::ostream& operator<<(std::ostream& os, const GuiAdapterKeyboardEvent& event);
+  std::ostream& operator<<(std::ostream& os, const GuiAdapterMouseEvent& event);
+
+  /*
+    Mousedown event trigger when either the left or right (or middle) mouse is pressed 
+    on the object;
+
+    Mouseup event trigger when either the left or right (or middle) mouse is released
+    above the object after triggered mousedown event and held.
+
+    Click event trigger when the only left mouse button is pressed and released on the
+    same object, requires the Mousedown and Mouseup event happened before Click event.
+
+    The normal expect trigger order: onMousedown >> onMouseup >> onClick
+
+    Testing in Chrome v58, the time between onMouseup and onClick events are around 
+    7ms to 15ms
+
+    FROM: https://codingrepo.com/javascript/2017/05/19/javascript-difference-mousedown-mouseup-click-events/
+  */
+#if ORTHANC_ENABLE_WASM == 1
+  void ConvertFromPlatform(GuiAdapterUiEvent& dest, int eventType, const EmscriptenUiEvent& src);
+
+  void ConvertFromPlatform(GuiAdapterMouseEvent& dest, int eventType, const EmscriptenMouseEvent& src);
+  
+  void ConvertFromPlatform(GuiAdapterWheelEvent& dest, int eventType, const EmscriptenWheelEvent& src);
+
+  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const EmscriptenKeyboardEvent& src);
+#else
+
+# if ORTHANC_ENABLE_SDL == 1
+  void ConvertFromPlatform(GuiAdapterMouseEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source);
+
+  void ConvertFromPlatform(GuiAdapterWheelEvent& dest, bool ctrlPressed, bool shiftPressed, bool altPressed, const SDL_Event& source);
+
+  void ConvertFromPlatform(GuiAdapterKeyboardEvent& dest, const SDL_Event& source);
+
+# endif
+
+#endif
+
+  typedef void (*GuiAdapterRunFunc)(void*);
+
+  class GuiAdapter
+  {
+  public:
+    GuiAdapter()
+    {
+      static int instanceCount = 0;
+      ORTHANC_ASSERT(instanceCount == 0);
+      instanceCount = 1;
+    }
+
+    /**
+      emscripten_set_resize_callback("EMSCRIPTEN_EVENT_TARGET_WINDOW", NULL, false, OnWindowResize);
+
+      emscripten_set_wheel_callback("#mycanvas1", widget1_.get(), false, OnXXXMouseWheel);
+      emscripten_set_wheel_callback("#mycanvas2", widget2_.get(), false, OnXXXMouseWheel);
+      emscripten_set_wheel_callback("#mycanvas3", widget3_.get(), false, OnXXXMouseWheel);
+
+      emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyDown); ---> NO!
+      emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, OnKeyUp);
+
+      emscripten_request_animation_frame_loop(OnAnimationFrame, NULL);
+    
+      SDL:
+      see https://wiki.libsdl.org/SDL_CaptureMouse
+
+    */
+
+    void SetMouseDownCallback       (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
+    void SetMouseDblClickCallback   (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
+    void SetMouseMoveCallback       (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
+    void SetMouseUpCallback         (std::string canvasId, void* userData, bool capture, OnMouseEventFunc   func);
+    void SetWheelCallback           (std::string canvasId, void* userData, bool capture, OnMouseWheelFunc   func);
+    void SetKeyDownCallback         (std::string canvasId, void* userData, bool capture, OnKeyDownFunc      func);
+    void SetKeyUpCallback           (std::string canvasId, void* userData, bool capture, OnKeyUpFunc        func);
+
+#if ORTHANC_ENABLE_SDL == 1
+
+    void SetGenericSdlEventCallback (std::string canvasId, void* userData, bool capture, OnSdlEventCallback func);
+
+    typedef bool (*OnSdlEventCallback)  (std::string canvasId, const SDL_Event& sdlEvent, void* userData);
+
+    // if you pass "#window", then any Window resize will trigger the callback
+    // (this special string is converted to EMSCRIPTEN_EVENT_TARGET_WINDOW in DOM, when DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1)
+    void SetSdlResizeCallback(std::string canvasId, 
+                              void* userData, 
+                              bool capture, 
+                              OnSdlWindowResizeFunc func);
+#endif
+
+    void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
+
+    // TODO: implement and call to remove canvases [in SDL, although code should be generic]
+    void SetOnExitCallback();
+
+    /**
+    Under SDL, this function does NOT return until all windows have been closed.
+    Under wasm, it returns without doing anything, since the event loop is managed
+    by the browser.
+    */
+    void Run(GuiAdapterRunFunc func = NULL, void* cookie = NULL);
+
+  private:
+
+#if ORTHANC_ENABLE_SDL == 1
+    /**
+    Gives observers a chance to react based on generic event handlers. This 
+    is used, for instance, when the viewport lock interface is invalidated.
+    */
+    void OnSdlGenericEvent(const SDL_Event& sdlEvent);
+#endif
+
+    /**
+    In SDL, this executes all the registered headers
+    */
+    void OnAnimationFrame();
+
+    //void RequestAnimationFrame(OnAnimationFrameFunc func, void* userData);
+    std::vector<std::pair<OnAnimationFrameFunc, void*> >  
+      animationFrameHandlers_;
+    
+    void OnResize(unsigned int width, unsigned int height);
+
+#if ORTHANC_ENABLE_SDL == 1
+    template<typename Func>
+    struct EventHandlerData
+    {
+      EventHandlerData(std::string canvasName, Func func, void* userData) 
+        : canvasName(canvasName)
+        , func(func)
+        , userData(userData)
+      {
+      }
+
+      std::string canvasName;
+      Func        func;
+      void*       userData;
+    };
+    std::vector<EventHandlerData<OnSdlWindowResizeFunc> > resizeHandlers_;
+    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseDownHandlers_;
+    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseDblCickHandlers_;
+    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseMoveHandlers_;
+    std::vector<EventHandlerData<OnMouseEventFunc  > >    mouseUpHandlers_;
+    std::vector<EventHandlerData<OnMouseWheelFunc  > >    mouseWheelHandlers_;
+    std::vector<EventHandlerData<OnKeyDownFunc > >        keyDownHandlers_;
+    std::vector<EventHandlerData<OnKeyUpFunc > >          keyUpHandlers_;
+    std::vector<EventHandlerData<OnSdlEventCallback > >   sdlEventHandlers_;
+
+    /**
+    This executes all the registered headers if needed (in wasm, the browser
+    deals with this)
+    */
+    void OnMouseEvent(uint32_t windowID, const GuiAdapterMouseEvent& event);
+
+    void OnKeyboardEvent(uint32_t windowID, const GuiAdapterKeyboardEvent& event);
+
+    /**
+    Same remark as OnMouseEvent
+    */
+    void OnMouseWheelEvent(uint32_t windowID, const GuiAdapterWheelEvent& event);
+
+#endif
+
+    /**
+    This executes all the registered headers if needed (in wasm, the browser
+    deals with this)
+    */
+    void ViewportsUpdateSize();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/NativeStoneApplicationContext.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,78 @@
+/**
+ * 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 "NativeStoneApplicationContext.h"
+#include "../../Platforms/Generic/OracleWebService.h"
+
+namespace OrthancStone
+{
+  void NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(
+    boost::shared_ptr<Deprecated::IWidget> widget)
+  {
+    that_.centralViewport_.SetCentralWidget(widget);
+  }
+
+
+  void NativeStoneApplicationContext::UpdateThread(NativeStoneApplicationContext* that)
+  {
+    while (!that->stopped_)
+    {
+      {
+        GlobalMutexLocker locker(*that);
+        locker.GetCentralViewport().DoAnimation();
+      }
+      
+      boost::this_thread::sleep(boost::posix_time::milliseconds(that->updateDelayInMs_));
+    }
+  }
+  
+
+  NativeStoneApplicationContext::NativeStoneApplicationContext() :
+    stopped_(true),
+    updateDelayInMs_(100)   // By default, 100ms between each refresh of the content
+  {
+    srand(static_cast<unsigned int>(time(NULL))); 
+  }
+
+
+  void NativeStoneApplicationContext::Start()
+  {
+    boost::recursive_mutex::scoped_lock lock(globalMutex_);
+    
+    if (stopped_ &&
+        centralViewport_.HasAnimation())
+    {
+      stopped_ = false;
+      updateThread_ = boost::thread(UpdateThread, this);
+    }
+  }
+
+
+  void NativeStoneApplicationContext::Stop()
+  {
+    stopped_ = true;
+    
+    if (updateThread_.joinable())
+    {
+      updateThread_.join();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/NativeStoneApplicationContext.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,78 @@
+/**
+ * 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/Deprecated/Viewport/WidgetViewport.h"
+#include "../../Framework/Deprecated/Volumes/ISlicedVolume.h"
+#include "../../Framework/Deprecated/Volumes/IVolumeLoader.h"
+
+#include <list>
+#include <boost/thread.hpp>
+#include "../StoneApplicationContext.h"
+
+namespace OrthancStone
+{
+  class NativeStoneApplicationContext : public StoneApplicationContext
+  {
+  private:
+    static void UpdateThread(NativeStoneApplicationContext* that);
+
+    boost::recursive_mutex    globalMutex_;
+    Deprecated::WidgetViewport  centralViewport_;
+    boost::thread   updateThread_;
+    bool            stopped_;
+    unsigned int    updateDelayInMs_;
+
+  public:
+    class GlobalMutexLocker: public boost::noncopyable
+    {
+    private:
+      NativeStoneApplicationContext&        that_;
+      boost::recursive_mutex::scoped_lock   lock_;
+      
+    public:
+      GlobalMutexLocker(NativeStoneApplicationContext& that) :
+        that_(that),
+        lock_(that.globalMutex_)
+      {
+      }
+
+      void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget);
+
+      Deprecated::IViewport& GetCentralViewport() 
+      {
+        return that_.centralViewport_;
+      }
+
+      void SetUpdateDelay(unsigned int delayInMs)
+      {
+        that_.updateDelayInMs_ = delayInMs;
+      }
+    };
+
+    NativeStoneApplicationContext();
+
+    void Start();
+
+    void Stop();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/NativeStoneApplicationRunner.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,265 @@
+/**
+ * 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/>.
+ **/
+
+
+#if ORTHANC_ENABLE_THREADS != 1
+#error this file shall be included only with the ORTHANC_ENABLE_THREADS set to 1
+#endif
+
+#include "NativeStoneApplicationRunner.h"
+
+#include "../../Framework/Deprecated/Toolbox/MessagingToolbox.h"
+#include "../../Platforms/Generic/OracleWebService.h"
+#include "../../Platforms/Generic/OracleDelayedCallExecutor.h"
+#include "NativeStoneApplicationContext.h"
+
+#include <Core/Logging.h>
+#include <Core/HttpClient.h>
+#include <Core/Toolbox.h>
+#include <Core/OrthancException.h>
+#include <Plugins/Samples/Common/OrthancHttpConnection.h>
+
+#include <boost/program_options.hpp>
+
+namespace OrthancStone
+{
+  // Anonymous namespace to avoid clashes against other compilation modules
+  namespace
+  {
+    class LogStatusBar : public Deprecated::IStatusBar
+    {
+    public:
+      virtual void ClearMessage()
+      {
+      }
+
+      virtual void SetMessage(const std::string& message)
+      {
+        LOG(WARNING) << message;
+      }
+    };
+  }
+
+  int NativeStoneApplicationRunner::Execute(int argc,
+                                            char* argv[])
+  {
+    /******************************************************************
+     * Initialize all the subcomponents of Orthanc Stone
+     ******************************************************************/
+
+    Orthanc::Logging::Initialize();
+    Orthanc::Toolbox::InitializeOpenSsl();
+    Orthanc::HttpClient::GlobalInitialize();
+
+    Initialize();
+
+    /******************************************************************
+     * Declare and parse the command-line options of the application
+     ******************************************************************/
+
+    boost::program_options::options_description options;
+
+    { // generic options
+      boost::program_options::options_description generic("Generic options");
+      generic.add_options()
+          ("help", "Display this help and exit")
+          ("verbose", "Be verbose in logs")
+          ("orthanc", boost::program_options::value<std::string>()->
+            default_value("http://localhost:8042/"),
+           "URL to the Orthanc server")
+          ("username", "Username for the Orthanc server")
+          ("password", "Password for the Orthanc server")
+          ("https-verify", boost::program_options::value<bool>()->
+            default_value(true), "Check HTTPS certificates")
+          ;
+
+      options.add(generic);
+    }
+
+    // platform specific options
+    DeclareCommandLineOptions(options);
+    
+    // application specific options
+    application_->DeclareStartupOptions(options);
+
+    boost::program_options::variables_map parameters;
+    bool error = false;
+
+    try
+    {
+      boost::program_options::store(
+        boost::program_options::command_line_parser(argc, argv).
+          options(options).allow_unregistered().run(), parameters);
+      boost::program_options::notify(parameters);
+    }
+    catch (boost::program_options::error& e)
+    {
+      LOG(ERROR) << 
+        "Error while parsing the command-line arguments: " << e.what();
+      error = true;
+    }
+
+
+    /******************************************************************
+     * Configure the application with the command-line parameters
+     ******************************************************************/
+
+    if (error || parameters.count("help"))
+    {
+      std::cout << std::endl;
+
+      std::cout << options << "\n";
+      return error ? -1 : 0;
+    }
+
+    if (parameters.count("https-verify") &&
+        !parameters["https-verify"].as<bool>())
+    {
+      LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)";
+      Orthanc::HttpClient::ConfigureSsl(false, "");
+    }
+
+    LOG(ERROR) << "???????? if (parameters.count(\"verbose\"))";
+    if (parameters.count("verbose"))
+    {
+      LOG(ERROR) << "parameters.count(\"verbose\") != 0";
+      Orthanc::Logging::EnableInfoLevel(true);
+      LOG(INFO) << "Verbose logs are enabled";
+    }
+
+    LOG(ERROR) << "???????? if (parameters.count(\"trace\"))";
+    if (parameters.count("trace"))
+    {
+      LOG(ERROR) << "parameters.count(\"trace\") != 0";
+      Orthanc::Logging::EnableTraceLevel(true);
+      VLOG(1) << "Trace logs are enabled";
+    }
+
+    ParseCommandLineOptions(parameters);
+
+    bool success = true;
+    try
+    {
+      /****************************************************************
+       * Initialize the connection to the Orthanc server
+       ****************************************************************/
+
+      Orthanc::WebServiceParameters webServiceParameters;
+
+      if (parameters.count("orthanc"))
+      {
+        webServiceParameters.SetUrl(parameters["orthanc"].as<std::string>());
+      }
+
+      if (parameters.count("username") && parameters.count("password"))
+      {
+        webServiceParameters.SetCredentials(parameters["username"].
+          as<std::string>(),
+          parameters["password"].as<std::string>());
+      }
+
+      LOG(WARNING) << "URL to the Orthanc REST API: " << 
+        webServiceParameters.GetUrl();
+
+      {
+        OrthancPlugins::OrthancHttpConnection orthanc(webServiceParameters);
+        if (!Deprecated::MessagingToolbox::CheckOrthancVersion(orthanc))
+        {
+          LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of "
+            << "Orthanc, please upgrade";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+        }
+      }
+
+
+      /****************************************************************
+       * Initialize the application
+       ****************************************************************/
+
+      LOG(WARNING) << "Creating the widgets of the application";
+
+      LogStatusBar statusBar;
+
+      NativeStoneApplicationContext context;
+
+      {
+        // use multiple threads to execute asynchronous tasks like 
+        // download content
+        Deprecated::Oracle oracle(6); 
+        oracle.Start();
+
+        {
+          boost::shared_ptr<Deprecated::OracleWebService> webService
+            (new Deprecated::OracleWebService(oracle, webServiceParameters, context));
+          context.SetWebService(webService);
+          context.SetOrthancBaseUrl(webServiceParameters.GetUrl());
+
+          Deprecated::OracleDelayedCallExecutor delayedExecutor(oracle, context);
+          context.SetDelayedCallExecutor(delayedExecutor);
+
+          application_->Initialize(&context, statusBar, parameters);
+
+          {
+            NativeStoneApplicationContext::GlobalMutexLocker locker(context);
+            locker.SetCentralWidget(application_->GetCentralWidget());
+            locker.GetCentralViewport().SetStatusBar(statusBar);
+          }
+
+          std::string title = application_->GetTitle();
+          if (title.empty())
+          {
+            title = "Stone of Orthanc";
+          }
+
+          /****************************************************************
+           * Run the application
+           ****************************************************************/
+
+          Run(context, title, argc, argv);
+
+          /****************************************************************
+           * Finalize the application
+           ****************************************************************/
+
+          oracle.Stop();
+        }
+      }
+
+      LOG(WARNING) << "The application is stopping";
+      application_->Finalize();
+    }
+    catch (Orthanc::OrthancException& e)
+    {
+      LOG(ERROR) << "EXCEPTION: " << e.What();
+      success = false;
+    }
+
+
+    /******************************************************************
+     * Finalize all the subcomponents of Orthanc Stone
+     ******************************************************************/
+
+    Finalize();
+    Orthanc::HttpClient::GlobalFinalize();
+    Orthanc::Toolbox::FinalizeOpenSsl();
+
+    return (success ? 0 : -1);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/NativeStoneApplicationRunner.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +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 "../IStoneApplication.h"
+
+#if ORTHANC_ENABLE_THREADS != 1
+#error this file shall be included only with the ORTHANC_ENABLE_THREADS set to 1
+#endif
+
+namespace OrthancStone
+{
+  class NativeStoneApplicationContext;
+
+  class NativeStoneApplicationRunner
+  {
+  protected:
+    boost::shared_ptr<IStoneApplication>  application_;
+    
+  public:
+    NativeStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application)
+      : application_(application)
+    {
+    }
+    int Execute(int argc,
+                char* argv[]);
+
+    virtual void Initialize() = 0;
+    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0;
+    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) = 0;
+
+    virtual void Run(NativeStoneApplicationContext& context, const std::string& title, int argc, char* argv[]) = 0;
+    virtual void Finalize() = 0;
+  };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Generic/Scene2DInteractor.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +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
+
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/IStoneApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,74 @@
+/**
+ * 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 "StoneApplicationContext.h"
+#include "../Framework/Deprecated/Viewport/WidgetViewport.h"
+
+#include <boost/program_options.hpp>
+#include <json/json.h>
+
+namespace OrthancStone
+{
+#if ORTHANC_ENABLE_QT==1
+  class QStoneMainWindow;
+#endif
+
+  // a StoneApplication is an application that can actually be executed
+  // in multiple environments.  i.e: it can run natively integrated in a QtApplication
+  // or it can be executed as part of a WebPage when compiled into WebAssembly.
+  class IStoneApplication : public boost::noncopyable
+  {
+  protected:
+    StoneApplicationContext* context_;
+
+  public:
+    virtual ~IStoneApplication()
+    {
+    }
+
+    virtual void DeclareStartupOptions(boost::program_options::options_description& options) = 0;
+    virtual void Initialize(StoneApplicationContext* context,
+                            Deprecated::IStatusBar& statusBar,
+                            const boost::program_options::variables_map& parameters) = 0;
+
+    /**
+      This method is meant to process messages received from the outside world (i.e. GUI)
+    */
+    virtual void HandleSerializedMessage(const char* data) = 0;
+
+#if ORTHANC_ENABLE_WASM==1
+    virtual void InitializeWasm() {}  // specific initialization when the app is running in WebAssembly.  This is called after the other Initialize()
+#endif
+#if ORTHANC_ENABLE_QT==1
+      virtual QStoneMainWindow* CreateQtMainWindow() = 0;
+#endif
+
+    virtual std::string GetTitle() const = 0;
+    
+    virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) = 0;
+    
+    virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() = 0;
+    
+    virtual void Finalize() = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Qt/QCairoWidget.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,238 @@
+/**
+ * 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 "QCairoWidget.h"
+
+#include <QPainter>
+#include <QPaintEvent>
+
+#include <stdexcept>
+
+
+QCairoWidget::StoneObserver::StoneObserver(QCairoWidget& that,
+                                           Deprecated::IViewport& viewport,
+                                           OrthancStone::MessageBroker& broker) :
+  OrthancStone::IObserver(broker),
+  that_(that)
+{
+  // get notified each time the content of the central viewport changes
+  viewport.RegisterObserverCallback(
+    new OrthancStone::Callable<StoneObserver, Deprecated::IViewport::ViewportChangedMessage>
+    (*this, &StoneObserver::OnViewportChanged));
+}
+
+
+QCairoWidget::QCairoWidget(QWidget *parent) :
+  QWidget(parent),
+  context_(NULL)
+{
+  setFocusPolicy(Qt::StrongFocus); // catch keyPressEvents
+}
+
+
+void QCairoWidget::SetContext(OrthancStone::NativeStoneApplicationContext& context)
+{
+  context_ = &context;
+
+  {
+    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+    observer_.reset(new StoneObserver(*this,
+                                      locker.GetCentralViewport(),
+                                      locker.GetMessageBroker()));
+  }
+}
+
+
+void QCairoWidget::paintEvent(QPaintEvent* /*event*/)
+{
+  QPainter painter(this);
+
+  if (image_.get() != NULL &&
+      context_ != NULL)
+  {
+    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+    Deprecated::IViewport& viewport = locker.GetCentralViewport();
+    Orthanc::ImageAccessor a;
+    surface_.GetWriteableAccessor(a);
+    viewport.Render(a);
+    painter.drawImage(0, 0, *image_);
+  }
+  else
+  {
+    painter.fillRect(rect(), Qt::red);
+  }
+}
+
+OrthancStone::KeyboardModifiers GetKeyboardModifiers(QInputEvent* event)
+{
+  Qt::KeyboardModifiers qtModifiers = event->modifiers();
+  int stoneModifiers = static_cast<int>(OrthancStone::KeyboardModifiers_None);
+  if ((qtModifiers & Qt::AltModifier) != 0)
+  {
+    stoneModifiers |= static_cast<int>(OrthancStone::KeyboardModifiers_Alt);
+  }
+  if ((qtModifiers & Qt::ControlModifier) != 0)
+  {
+    stoneModifiers |= static_cast<int>(OrthancStone::KeyboardModifiers_Control);
+  }
+  if ((qtModifiers & Qt::ShiftModifier) != 0)
+  {
+    stoneModifiers |= static_cast<int>(OrthancStone::KeyboardModifiers_Shift);
+  }
+  return static_cast<OrthancStone::KeyboardModifiers>(stoneModifiers);
+}
+
+void QCairoWidget::mousePressEvent(QMouseEvent* event)
+{
+  OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
+
+  OrthancStone::MouseButton button;
+
+  switch (event->button())
+  {
+    case Qt::LeftButton:
+      button = OrthancStone::MouseButton_Left;
+      break;
+
+    case Qt::RightButton:
+      button = OrthancStone::MouseButton_Right;
+      break;
+
+    case Qt::MiddleButton:
+      button = OrthancStone::MouseButton_Middle;
+      break;
+
+    default:
+      return;  // Unsupported button
+  }
+
+  {
+    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+    locker.GetCentralViewport().MouseDown(button, event->pos().x(), event->pos().y(), stoneModifiers, std::vector<Deprecated::Touch>());
+  }
+}
+
+
+void QCairoWidget::mouseReleaseEvent(QMouseEvent* /*eventNotUsed*/)
+{
+  OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+  locker.GetCentralViewport().MouseLeave();
+}
+
+
+void QCairoWidget::mouseMoveEvent(QMouseEvent* event)
+{
+  OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+  locker.GetCentralViewport().MouseMove(event->pos().x(), event->pos().y(), std::vector<Deprecated::Touch>());
+}
+
+
+void QCairoWidget::wheelEvent(QWheelEvent * event)
+{
+  OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+
+  OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
+
+  if (event->orientation() == Qt::Vertical)
+  {
+    if (event->delta() < 0)  // TODO: compare direction with SDL and make sure we send the same directions
+    {
+       locker.GetCentralViewport().MouseWheel(OrthancStone::MouseWheelDirection_Up, event->pos().x(), event->pos().y(), stoneModifiers);
+    }
+    else
+    {
+      locker.GetCentralViewport().MouseWheel(OrthancStone::MouseWheelDirection_Down, event->pos().x(), event->pos().y(), stoneModifiers);
+    }
+  }
+}
+
+void QCairoWidget::keyPressEvent(QKeyEvent *event)
+{
+  using namespace OrthancStone;
+
+  OrthancStone::KeyboardModifiers stoneModifiers = GetKeyboardModifiers(event);
+
+  OrthancStone::KeyboardKeys keyType = OrthancStone::KeyboardKeys_Generic;
+  char keyChar = event->text()[0].toLatin1();
+
+#define CASE_QT_KEY_TO_ORTHANC(qt, o) case qt: keyType = o; break;
+  if (keyChar == 0)
+  {
+    switch (event->key())
+    {
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Up, KeyboardKeys_Up);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Down, KeyboardKeys_Down);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Left, KeyboardKeys_Left);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Right, KeyboardKeys_Right);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F1, KeyboardKeys_F1);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F2, KeyboardKeys_F2);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F3, KeyboardKeys_F3);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F4, KeyboardKeys_F4);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F5, KeyboardKeys_F5);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F6, KeyboardKeys_F6);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F7, KeyboardKeys_F7);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F8, KeyboardKeys_F8);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F9, KeyboardKeys_F9);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F10, KeyboardKeys_F10);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F11, KeyboardKeys_F11);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_F12, KeyboardKeys_F12);
+    default:
+      break;
+    }
+  }
+  else if (keyChar == 127)
+  {
+    switch (event->key())
+    {
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Delete, KeyboardKeys_Delete);
+      CASE_QT_KEY_TO_ORTHANC(Qt::Key_Backspace, KeyboardKeys_Backspace);
+    default:
+      break;
+    }
+  }
+
+  {
+    OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);    
+    locker.GetCentralViewport().KeyPressed(keyType, keyChar, stoneModifiers);
+  }
+}
+
+
+void QCairoWidget::resizeEvent(QResizeEvent* event)
+{
+  grabGesture(Qt::PanGesture);
+  QWidget::resizeEvent(event);
+
+  if (event)
+  {
+    surface_.SetSize(event->size().width(), event->size().height(), true);
+
+    image_.reset(new QImage(reinterpret_cast<uchar*>(surface_.GetBuffer()),
+                            event->size().width(), 
+                            event->size().height(),
+                            surface_.GetPitch(),
+                            QImage::Format_RGB32));
+
+    {
+      OrthancStone::NativeStoneApplicationContext::GlobalMutexLocker locker(*context_);
+      locker.GetCentralViewport().SetSize(event->size().width(), event->size().height());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Qt/QCairoWidget.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,88 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+4 * 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/NativeStoneApplicationContext.h"
+#include "../../Framework/Wrappers/CairoSurface.h"
+#include "../../Framework/Deprecated/Widgets/IWidget.h"
+
+#include <QWidget>
+#include <memory>
+#include <cassert>
+
+class QCairoWidget : public QWidget
+{
+  Q_OBJECT
+
+private:
+  class StoneObserver : public OrthancStone::IObserver
+  {
+  private:
+    QCairoWidget& that_;
+    
+  public:
+    StoneObserver(QCairoWidget& that,
+                  Deprecated::IViewport& viewport,
+                  OrthancStone::MessageBroker& broker);
+
+    void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
+    {
+      that_.OnViewportChanged();
+    }
+  };
+  
+  std::unique_ptr<QImage>         image_;
+  OrthancStone::CairoSurface    surface_;
+  OrthancStone::NativeStoneApplicationContext* context_;
+  std::unique_ptr<StoneObserver>  observer_;
+
+protected:
+  virtual void paintEvent(QPaintEvent *event);
+
+  virtual void resizeEvent(QResizeEvent *event);
+
+  virtual void mouseMoveEvent(QMouseEvent *event);
+
+  virtual void mousePressEvent(QMouseEvent *event);
+
+  virtual void mouseReleaseEvent(QMouseEvent *event);
+
+  virtual void wheelEvent(QWheelEvent *event);
+
+  virtual void keyPressEvent(QKeyEvent *event);
+
+public:
+  explicit QCairoWidget(QWidget *parent);
+ 
+  void SetContext(OrthancStone::NativeStoneApplicationContext& context);
+
+  void OnViewportChanged()
+  {
+    update();  // schedule a repaint (handled by Qt)
+    emit ContentChanged();
+  }
+
+signals:
+  void ContentChanged();
+                                               
+public slots:
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Qt/QStoneMainWindow.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,43 @@
+/**
+ * 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 "QStoneMainWindow.h"
+
+namespace OrthancStone
+{
+
+  QStoneMainWindow::QStoneMainWindow(NativeStoneApplicationContext& context,
+                                     QWidget *parent) :
+    QMainWindow(parent),
+    context_(context),
+    cairoCentralWidget_(NULL)
+  {
+  }
+
+  void QStoneMainWindow::SetCentralStoneWidget(QCairoWidget& centralWidget)
+  {
+    cairoCentralWidget_ = &centralWidget;
+    cairoCentralWidget_->SetContext(context_);
+  }
+
+  QStoneMainWindow::~QStoneMainWindow()
+  {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Qt/QStoneMainWindow.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,45 @@
+/**
+ * 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 <QMainWindow>
+
+#include "QCairoWidget.h"
+#include "../Generic/NativeStoneApplicationContext.h"
+
+namespace OrthancStone
+{
+  class QStoneMainWindow : public QMainWindow
+  {
+    Q_OBJECT
+
+  private:
+    OrthancStone::NativeStoneApplicationContext& context_;
+    QCairoWidget          *cairoCentralWidget_;
+
+  protected:  // you must inherit this class
+    QStoneMainWindow(NativeStoneApplicationContext& context, QWidget *parent = 0);
+    void SetCentralStoneWidget(QCairoWidget& centralWidget);
+
+  public:
+    virtual ~QStoneMainWindow();
+  };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Qt/QtStoneApplicationRunner.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,67 @@
+/**
+ * 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/>.
+ **/
+
+
+#if ORTHANC_ENABLE_QT != 1
+#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
+#endif
+
+#include "QtStoneApplicationRunner.h"
+#include <boost/program_options.hpp>
+#include <QApplication>
+
+#include "../../Framework/Deprecated/Toolbox/MessagingToolbox.h"
+
+#include <Core/Logging.h>
+#include <Core/HttpClient.h>
+#include <Core/Toolbox.h>
+#include <Plugins/Samples/Common/OrthancHttpConnection.h>
+#include "../../Platforms/Generic/OracleWebService.h"
+
+
+namespace OrthancStone
+{
+  void QtStoneApplicationRunner::Initialize()
+  {
+  }
+
+  void QtStoneApplicationRunner::DeclareCommandLineOptions(boost::program_options::options_description& options)
+  {
+  }
+
+  void QtStoneApplicationRunner::Run(NativeStoneApplicationContext& context, const std::string& title, int argc, char* argv[])
+  {
+    context.Start();
+
+    QApplication qtApplication(argc, argv);
+    window_.reset(application_.CreateQtMainWindow());
+
+    window_->show();
+    qtApplication.exec();
+
+    context.Stop();
+  }
+
+  void QtStoneApplicationRunner::Finalize()
+  {
+  }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Qt/QtStoneApplicationRunner.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,54 @@
+/**
+ * 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 "../Generic/NativeStoneApplicationRunner.h"
+#include "QStoneMainWindow.h"
+
+#if ORTHANC_ENABLE_QT != 1
+#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
+#endif
+
+namespace OrthancStone
+{
+  class QtStoneApplicationRunner : public NativeStoneApplicationRunner
+  {
+  protected:
+    std::unique_ptr<QStoneMainWindow> window_;
+
+  public:
+    QtStoneApplicationRunner(MessageBroker& broker,
+                             IStoneApplication& application)
+      : NativeStoneApplicationRunner(broker, application)
+    {
+    }
+
+
+    virtual void Initialize();
+
+    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
+    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters) {}
+    virtual void Run(NativeStoneApplicationContext& context, const std::string& title, int argc, char* argv[]);
+    virtual void Finalize();
+  };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/BasicPetCtFusionApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,202 @@
+/**
+ * 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 "SampleInteractor.h"
+
+#include <Core/Logging.h>
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class BasicPetCtFusionApplication : public SampleApplicationBase
+    {
+    private:
+      class Interactor : public SampleInteractor
+      {
+      public:
+        static void SetStyle(LayeredSceneWidget& widget,
+                             bool ct,
+                             bool pet)
+        {
+          if (ct)
+          {
+            RenderStyle style;
+            style.windowing_ = ImageWindowing_Bone;
+            widget.SetLayerStyle(0, style);
+          }
+          else
+          {
+            RenderStyle style;
+            style.visible_ = false;
+            widget.SetLayerStyle(0, style);
+          }
+
+          if (ct && pet)
+          {
+            RenderStyle style;
+            style.applyLut_ = true;
+            style.alpha_ = 0.5;
+            widget.SetLayerStyle(1, style);
+          }
+          else if (pet)
+          {
+            RenderStyle style;
+            style.applyLut_ = true;
+            widget.SetLayerStyle(1, style);
+          }
+          else
+          {
+            RenderStyle style;
+            style.visible_ = false;
+            widget.SetLayerStyle(1, style);
+          }
+        }
+
+
+        static bool IsVisible(LayeredSceneWidget& widget,
+                              size_t layer)
+        {
+          RenderStyle style = widget.GetLayerStyle(layer);
+          return style.visible_;
+        }
+
+
+        static void ToggleInterpolation(LayeredSceneWidget& widget,
+                                        size_t layer)
+        {
+          RenderStyle style = widget.GetLayerStyle(layer);
+         
+          if (style.interpolation_ == ImageInterpolation_Bilinear)
+          {
+            style.interpolation_ = ImageInterpolation_Nearest;
+          }
+          else
+          {
+            style.interpolation_ = ImageInterpolation_Bilinear;
+          }
+
+          widget.SetLayerStyle(layer, style);
+        }
+
+
+        Interactor(VolumeImage& volume,
+                   VolumeProjection projection, 
+                   bool reverse) :
+          SampleInteractor(volume, projection, reverse)
+        {
+        }
+
+
+        virtual void KeyPressed(WorldSceneWidget& widget,
+                                char key,
+                                KeyboardModifiers modifiers,
+                                IStatusBar* statusBar)
+        {
+          LayeredSceneWidget& layered = dynamic_cast<LayeredSceneWidget&>(widget);
+
+          switch (key)
+          {
+            case 'c':
+              // Toggle the visibility of the CT layer
+              SetStyle(layered, !IsVisible(layered, 0), IsVisible(layered, 1));
+              break;
+
+            case 'p':
+              // Toggle the visibility of the PET layer
+              SetStyle(layered, IsVisible(layered, 0), !IsVisible(layered, 1));
+              break;
+
+            case 'i':
+            {
+              // Toggle on/off the interpolation
+              ToggleInterpolation(layered, 0);
+              ToggleInterpolation(layered, 1);
+              break;
+            }
+
+            default:
+              break;
+          }
+        }
+      };
+
+
+    public:
+      virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("ct", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the CT series")
+          ("pet", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the PET series")
+          ("threads", boost::program_options::value<unsigned int>()->default_value(3), 
+           "Number of download threads for the CT series")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(BasicApplicationContext& context,
+                              IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        if (parameters.count("ct") != 1 ||
+            parameters.count("pet") != 1)
+        {
+          LOG(ERROR) << "The series ID is missing";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::string ct = parameters["ct"].as<std::string>();
+        std::string pet = parameters["pet"].as<std::string>();
+        unsigned int threads = parameters["threads"].as<unsigned int>();
+
+        VolumeImage& ctVolume = context.AddSeriesVolume(ct, true /* progressive download */, threads);
+        VolumeImage& petVolume = context.AddSeriesVolume(pet, true /* progressive download */, 1);
+
+        // Take the PET volume as the reference for the slices
+        std::unique_ptr<Interactor> interactor(new Interactor(petVolume, VolumeProjection_Axial, false /* don't reverse normal */));
+
+        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
+        widget->AddLayer(new VolumeImage::LayerFactory(ctVolume));
+        widget->AddLayer(new VolumeImage::LayerFactory(petVolume));
+        widget->SetSlice(interactor->GetCursor().GetCurrentSlice());
+        widget->SetInteractor(*interactor);
+
+        Interactor::SetStyle(*widget, true, true);   // Initially, show both CT and PET layers
+
+        context.AddInteractor(interactor.release());
+        context.SetCentralWidget(widget.release());
+
+        statusBar.SetMessage("Use the key \"t\" to toggle the fullscreen mode");
+        statusBar.SetMessage("Use the key \"c\" to show/hide the CT layer");
+        statusBar.SetMessage("Use the key \"p\" to show/hide the PET layer");
+        statusBar.SetMessage("Use the key \"i\" to toggle the smoothing of the images");
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/CMakeLists.txt	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,292 @@
+# Usage (Linux):
+# to build the WASM samples
+# source ~/Downloads/emsdk/emsdk_env.sh && cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
+# to build the Qt samples
+
+cmake_minimum_required(VERSION 2.8.3)
+project(OrthancStone)
+
+include(../../../Resources/CMake/OrthancStoneParameters.cmake)
+
+set(ENABLE_STONE_DEPRECATED ON)  # Need deprecated classes for these samples
+set(EMSCRIPTEN_SET_LLVM_WASM_BACKEND ON)
+
+include(${ORTHANC_ROOT}/Resources/CMake/DownloadPackage.cmake)
+DownloadPackage(
+  "a24b8136b8f3bb93f166baf97d9328de"
+  "http://orthanc.osimis.io/ThirdPartyDownloads/ubuntu-font-family-0.83.zip"
+  "${CMAKE_BINARY_DIR}/ubuntu-font-family-0.83")
+
+set(ORTHANC_STONE_APPLICATION_RESOURCES
+  UBUNTU_FONT  ${CMAKE_BINARY_DIR}/ubuntu-font-family-0.83/Ubuntu-R.ttf
+  )
+
+if (OPENSSL_NO_CAPIENG)
+add_definitions(-DOPENSSL_NO_CAPIENG=1)
+endif()
+
+
+# the following block has been borrowed from orthanc/**/Compiler.cmake
+if (MSVC_MULTIPLE_PROCESSES)
+# "If you omit the processMax argument in the /MP option, the
+# compiler obtains the number of effective processors from the
+# operating system, and then creates one process per effective
+# processor"
+# https://blog.kitware.com/cmake-building-with-all-your-cores/
+# https://docs.microsoft.com/en-us/cpp/build/reference/mp-build-with-multiple-processes
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
+endif()
+
+#set(ENABLE_DCMTK ON)
+
+set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
+set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
+set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
+
+if (ENABLE_WASM)
+  #####################################################################
+  ## Configuration of the Emscripten compiler for WebAssembly target
+  #####################################################################
+
+  set(WASM_FLAGS "-s WASM=1")
+  set(WASM_FLAGS "${WASM_FLAGS} -s STRICT=1") # drops support for all deprecated build options
+  set(WASM_FLAGS "${WASM_FLAGS} -s FILESYSTEM=1") # if we don't include it, gen_uuid.c fails to build because srand, getpid(), ... are not defined
+  set(WASM_FLAGS "${WASM_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0") # actually enable exception catching 
+  set(WASM_FLAGS "${WASM_FLAGS} -s ERROR_ON_MISSING_LIBRARIES=1")
+  
+  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
+    set(WASM_FLAGS "${WASM_FLAGS} -g4") # generate debug information
+    set(WASM_FLAGS "${WASM_FLAGS} -s ASSERTIONS=2") # more runtime checks
+  else()
+    set(WASM_FLAGS "${WASM_FLAGS} -Os") # optimize for web (speed and size)
+  endif()
+
+  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
+
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
+
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_FLAGS}")  # not always clear which flags are for the compiler and which one are for the linker -> pass them all to the linker too
+  # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"'")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=128000000")
+
+  add_definitions(-DORTHANC_ENABLE_WASM=1)
+  set(ORTHANC_SANDBOXED ON)
+
+elseif (ENABLE_QT OR ENABLE_SDL)
+
+  set(ENABLE_NATIVE ON)
+  set(ORTHANC_SANDBOXED OFF)
+  set(ENABLE_CRYPTO_OPTIONS ON)
+  set(ENABLE_GOOGLE_TEST ON)
+  set(ENABLE_WEB_CLIENT ON)
+
+else()
+  set(ENABLE_NATIVE ON)
+  set(ENABLE_OPENGL OFF)
+  
+endif()
+
+
+#####################################################################
+## Configuration for Orthanc
+#####################################################################
+
+# include(../../Resources/CMake/Version.cmake)
+
+if (ORTHANC_STONE_VERSION STREQUAL "mainline")
+  set(ORTHANC_FRAMEWORK_VERSION "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
+else()
+  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
+endif()
+
+set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
+set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
+set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
+
+add_definitions(
+  -DORTHANC_ENABLE_LOGGING_PLUGIN=0
+  )
+
+
+#####################################################################
+## Build a static library containing the Orthanc Stone framework
+#####################################################################
+
+
+LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
+
+include(../../../Resources/CMake/OrthancStoneConfiguration.cmake)
+
+add_library(OrthancStone STATIC
+  ${ORTHANC_STONE_SOURCES}
+  )
+
+#####################################################################
+## Build all the sample applications
+#####################################################################
+
+include_directories(${ORTHANC_STONE_ROOT})
+
+# files common to all samples
+list(APPEND SAMPLE_APPLICATIONS_SOURCES
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleInteractor.h
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleApplicationBase.h
+  )
+
+if (ENABLE_QT)
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleQtApplicationRunner.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindow.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.cpp
+    )
+
+  ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindow.ui
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.ui
+    )
+
+  ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.h
+    )
+endif()
+
+if (ENABLE_NATIVE)
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleMainNative.cpp
+    )
+
+elseif (ENABLE_WASM)
+
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SampleMainWasm.cpp
+    ${STONE_WASM_SOURCES}
+    )
+endif()
+
+
+macro(BuildSingleFileSample Target Header Sample)
+  add_executable(${Target}
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/${Header}
+    ${SAMPLE_APPLICATIONS_SOURCES}
+    )
+  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
+  target_link_libraries(${Target} OrthancStone)
+endmacro()
+
+
+if (ENABLE_SDL)
+  #BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
+  #BuildSingleFileSample(OrthancStoneTestPattern TestPatternApplication.h 2)
+  BuildSingleFileSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
+  #BuildSingleFileSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
+  #BuildSingleFileSample(OrthancStoneBasicPetCtFusion 5)
+  #BuildSingleFileSample(OrthancStoneSynchronizedSeries 6)
+  #BuildSingleFileSample(OrthancStoneLayoutPetCtFusion 7)
+  BuildSingleFileSample(OrthancStoneSimpleViewerSingleFile SimpleViewerApplicationSingleFile.h 8)  # we keep that one just as a sample before we convert another sample to this pattern
+  BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
+endif()
+  
+##### SimpleViewer sample (Qt and WASM only) #######
+
+if (ENABLE_QT OR ENABLE_WASM)
+
+    if (ENABLE_QT)
+      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.cpp
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/mainQt.cpp
+        )
+
+      ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        )
+
+      ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.h
+        )
+
+elseif (ENABLE_WASM)
+        list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Wasm/mainWasm.cpp
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.h
+            ${STONE_WASM_SOURCES}
+          )
+    endif()
+
+    add_executable(OrthancStoneSimpleViewer
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/AppStatus.h
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.h
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.h
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.h
+      ${SIMPLE_VIEWER_APPLICATION_SOURCES}
+      )
+    target_link_libraries(OrthancStoneSimpleViewer OrthancStone)
+
+    BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
+endif()
+
+#####################################################################
+## Build the unit tests
+#####################################################################
+
+if (ENABLE_NATIVE)
+  add_executable(UnitTests
+    ${GOOGLE_TEST_SOURCES}
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/GenericToolboxTests.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/ImageToolboxTests.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/PixelTestPatternsTests.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStrategy.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStructureSet.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
+    )
+
+  target_link_libraries(UnitTests OrthancStone)
+
+  add_custom_command(
+    TARGET UnitTests
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "${ORTHANC_STONE_ROOT}/UnitTestsSources/72c773ac-5059f2c4-2e6a9120-4fd4bca1-45701661.json" 
+      "$<TARGET_FILE_DIR:UnitTests>/72c773ac-5059f2c4-2e6a9120-4fd4bca1-45701661.json"
+    )
+
+endif()
+
+#####################################################################
+## Generate the documentation if Doxygen is present
+#####################################################################
+
+find_package(Doxygen)
+if (DOXYGEN_FOUND)
+  configure_file(
+    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
+    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    @ONLY)
+
+  add_custom_target(doc
+    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    COMMENT "Generating documentation with Doxygen" VERBATIM
+    )
+else()
+  message("Doxygen not found. The documentation will not be built.")
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/CMakeLists.txt.old	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,248 @@
+# Usage: see README file
+
+cmake_minimum_required(VERSION 2.8.3)
+
+# Automatically link Qt executables to qtmain target on Windows
+# ("OLD" == do not link)
+if(POLICY CMP0020)
+  cmake_policy(SET CMP0020 OLD)
+endif()
+
+# Only interpret if() arguments as variables or keywords when unquoted.
+# NEW = do NOT dereference *quoted* variables
+if(POLICY CMP0054)
+  cmake_policy(SET CMP0054 NEW)
+endif()
+
+project(OrthancStone)
+
+include(../../Resources/CMake/OrthancStoneParameters.cmake)
+
+#set(ENABLE_DCMTK ON)
+
+set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
+set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
+set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
+
+# TODO: replace or compute STONE_SOURCES_DIR from CMAKE_CURRENT_LIST_FILE
+
+if (ENABLE_WASM)
+  #####################################################################
+  ## Configuration of the Emscripten compiler for WebAssembly target
+  #####################################################################
+
+  set(WASM_FLAGS "-s WASM=1 -O0 -g0")
+  message("*****************************************************************************")
+  message("WARNING: optimizations are disabled in emcc!!! Enable them for production use")
+  message("*****************************************************************************")
+  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js  -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
+
+  # Handling of memory
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")  # Resize
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")  # 512MB
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=536870912 -s TOTAL_STACK=128000000")  # 512MB + resize
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=1073741824")  # 1GB + resize
+
+  # To debug exceptions
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2")
+
+  add_definitions(-DORTHANC_ENABLE_WASM=1)
+  set(ORTHANC_SANDBOXED ON)
+
+elseif (ENABLE_QT OR ENABLE_SDL)
+
+  set(ENABLE_NATIVE ON)
+  set(ORTHANC_SANDBOXED OFF)
+  set(ENABLE_CRYPTO_OPTIONS ON)
+  set(ENABLE_GOOGLE_TEST ON)
+  set(ENABLE_WEB_CLIENT ON)
+
+endif()
+
+#####################################################################
+## Configuration for Orthanc
+#####################################################################
+
+# include(../../Resources/CMake/Version.cmake)
+
+if (ORTHANC_STONE_VERSION STREQUAL "mainline")
+  set(ORTHANC_FRAMEWORK_VERSION "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
+else()
+  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
+endif()
+
+set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
+set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
+set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
+
+#####################################################################
+## Build a static library containing the Orthanc Stone framework
+#####################################################################
+
+LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
+
+include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
+
+add_library(OrthancStone STATIC
+  ${ORTHANC_STONE_SOURCES}
+  )
+
+#####################################################################
+## Build all the sample applications
+#####################################################################
+
+include_directories(${ORTHANC_STONE_ROOT})
+
+# files common to all samples
+list(APPEND SAMPLE_APPLICATIONS_SOURCES
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
+  )
+
+if (ENABLE_QT)
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp
+    )
+
+  ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.ui
+    )
+
+  ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.h
+    )
+endif()
+
+if (ENABLE_NATIVE)
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainNative.cpp
+    )
+
+elseif (ENABLE_WASM)
+
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainWasm.cpp
+    ${STONE_WASM_SOURCES}
+    )
+endif()
+
+
+macro(BuildSingleFileSample Target Header Sample)
+  add_executable(${Target}
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header}
+    ${SAMPLE_APPLICATIONS_SOURCES}
+    )
+  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
+  target_link_libraries(${Target} OrthancStone)
+  
+  if (ENABLE_QT AND (CMAKE_SYSTEM_NAME STREQUAL "Windows"))
+    message("(ENABLE_QT and (CMAKE_SYSTEM_NAME matches \"Windows\")) is true")
+    add_custom_command(
+      TARGET ${Target} POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:${Target}>
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${Target}>
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:${Target}>
+    )
+  endif()
+endmacro()
+
+#BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
+#BuildSingleFileSample(OrthancStoneTestPattern TestPatternApplication.h 2)
+BuildSingleFileSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
+#BuildSingleFileSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
+#BuildSingleFileSample(OrthancStoneBasicPetCtFusion 5)
+#BuildSingleFileSample(OrthancStoneSynchronizedSeries 6)
+#BuildSingleFileSample(OrthancStoneLayoutPetCtFusion 7)
+BuildSingleFileSample(OrthancStoneSimpleViewerSingleFile SimpleViewerApplicationSingleFile.h 8)  # we keep that one just as a sample before we convert another sample to this pattern
+BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
+
+##### SimpleViewer sample (Qt and WASM only) #######
+
+if (ENABLE_QT OR ENABLE_WASM)
+
+      # GenerateCodeFromFlatBufferSchema("${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ApplicationCommands.fbs")
+
+      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES ${FLATC_AUTOGENERATED_SOURCES})
+      message(STATUS "SIMPLE_VIEWER_APPLICATION_SOURCES = ${SIMPLE_VIEWER_APPLICATION_SOURCES}")
+      message(STATUS "FLATC_AUTOGENERATED_SOURCES = ${FLATC_AUTOGENERATED_SOURCES}")
+
+    if (ENABLE_QT)
+      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.cpp
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/mainQt.cpp
+        )
+
+      ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        )
+
+      ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.h
+        )
+
+elseif (ENABLE_WASM)
+        list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/mainWasm.cpp
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp
+            ${STONE_WASM_SOURCES}
+          )
+    endif()
+
+    add_executable(OrthancStoneSimpleViewer
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/AppStatus.h
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Messages.h
+      ${SIMPLE_VIEWER_APPLICATION_SOURCES}
+      )
+    target_link_libraries(OrthancStoneSimpleViewer OrthancStone)
+
+endif()
+
+#####################################################################
+## Build the unit tests
+#####################################################################
+
+if (ENABLE_NATIVE)
+  add_executable(UnitTests
+    ${GOOGLE_TEST_SOURCES}
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestExceptions.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
+    )
+
+  target_link_libraries(UnitTests OrthancStone)
+endif()
+
+#####################################################################
+## Generate the documentation if Doxygen is present
+#####################################################################
+
+find_package(Doxygen)
+if (DOXYGEN_FOUND)
+  configure_file(
+    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
+    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    @ONLY)
+
+  add_custom_target(doc
+    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    COMMENT "Generating documentation with Doxygen" VERBATIM
+    )
+else()
+  message("Doxygen not found. The documentation will not be built.")
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/EmptyApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,58 @@
+/**
+ * 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 "SampleApplicationBase.h"
+
+#include "../../../Framework/Widgets/EmptyWidget.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class EmptyApplication : public SampleApplicationBase
+    {
+    public:
+      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("red", boost::program_options::value<int>()->default_value(255), "Background color: red channel")
+          ("green", boost::program_options::value<int>()->default_value(0), "Background color: green channel")
+          ("blue", boost::program_options::value<int>()->default_value(0), "Background color: blue channel")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        int red = parameters["red"].as<int>();
+        int green = parameters["green"].as<int>();
+        int blue = parameters["blue"].as<int>();
+
+        context_->SetCentralWidget(new EmptyWidget(red, green, blue));
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/LayoutPetCtFusionApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,398 @@
+/**
+ * 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 "SampleInteractor.h"
+
+#include "../../../Framework/Layers/ReferenceLineFactory.h"
+#include "../../../Framework/Layers/DicomStructureSetSlicer.h"
+#include "../../../Framework/Widgets/LayoutWidget.h"
+
+#include <Core/Logging.h>
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class LayoutPetCtFusionApplication : 
+      public SampleApplicationBase,
+      public LayeredSceneWidget::ISliceObserver,
+      public WorldSceneWidget::IWorldObserver
+    {
+    private:
+      class Interactor : public SampleInteractor
+      {
+      private:
+        LayoutPetCtFusionApplication& that_;
+
+      public:
+        Interactor(LayoutPetCtFusionApplication& that,
+                   VolumeImage& volume,
+                   VolumeProjection projection, 
+                   bool reverse) :
+          SampleInteractor(volume, projection, reverse),
+          that_(that)
+        {
+        }
+
+        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                            const SliceGeometry& slice,
+                                                            const ViewportGeometry& view,
+                                                            MouseButton button,
+                                                            double x,
+                                                            double y,
+                                                            IStatusBar* statusBar)
+        {
+          if (button == MouseButton_Left)
+          {
+            // Center the sibling views over the clicked point
+            Vector p = slice.MapSliceToWorldCoordinates(x, y);
+
+            if (statusBar != NULL)
+            {
+              char buf[64];
+              sprintf(buf, "Click on coordinates (%.02f,%.02f,%.02f) in cm", p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+              statusBar->SetMessage(buf);
+            }
+
+            that_.interactorAxial_->LookupSliceContainingPoint(*that_.ctAxial_, p);
+            that_.interactorCoronal_->LookupSliceContainingPoint(*that_.ctCoronal_, p);
+            that_.interactorSagittal_->LookupSliceContainingPoint(*that_.ctSagittal_, p);
+          }
+
+          return NULL;
+        }
+
+        virtual void KeyPressed(WorldSceneWidget& widget,
+                                char key,
+                                KeyboardModifiers modifiers,
+                                IStatusBar* statusBar)
+        {
+          if (key == 's')
+          {
+            that_.FitContent();
+          }
+        }
+      };
+
+      bool                 processingEvent_;
+      Interactor*          interactorAxial_;
+      Interactor*          interactorCoronal_;
+      Interactor*          interactorSagittal_;
+      LayeredSceneWidget*  ctAxial_;
+      LayeredSceneWidget*  ctCoronal_;
+      LayeredSceneWidget*  ctSagittal_;
+      LayeredSceneWidget*  petAxial_;
+      LayeredSceneWidget*  petCoronal_;
+      LayeredSceneWidget*  petSagittal_;
+      LayeredSceneWidget*  fusionAxial_;
+      LayeredSceneWidget*  fusionCoronal_;
+      LayeredSceneWidget*  fusionSagittal_;
+
+
+      void FitContent()
+      {
+        petAxial_->FitContent();
+        petCoronal_->FitContent();
+        petSagittal_->FitContent();
+      }
+
+
+      void AddLayer(LayeredSceneWidget& widget,
+                    VolumeImage& volume,
+                    bool isCt)
+      {
+        size_t layer;
+        widget.AddLayer(layer, new VolumeImage::LayerFactory(volume));
+
+        if (isCt)
+        {
+          RenderStyle style; 
+          style.windowing_ = ImageWindowing_Bone;
+          widget.SetLayerStyle(layer, style);
+        }
+        else
+        {
+          RenderStyle style; 
+          style.applyLut_ = true;
+          style.alpha_ = (layer == 0 ? 1.0f : 0.5f);
+          widget.SetLayerStyle(layer, style);
+        }
+      }
+
+
+      void ConnectSiblingLocations(LayeredSceneWidget& axial,
+                                   LayeredSceneWidget& coronal,
+                                   LayeredSceneWidget& sagittal)
+      {
+        ReferenceLineFactory::Configure(axial, coronal);
+        ReferenceLineFactory::Configure(axial, sagittal);
+        ReferenceLineFactory::Configure(coronal, sagittal);
+      }
+
+
+      void SynchronizeView(const WorldSceneWidget& source,
+                           const ViewportGeometry& view,
+                           LayeredSceneWidget& widget1,
+                           LayeredSceneWidget& widget2,
+                           LayeredSceneWidget& widget3)
+      {
+        if (&source == &widget1 ||
+            &source == &widget2 ||
+            &source == &widget3)
+        {
+          if (&source != &widget1)
+          {
+            widget1.SetView(view);
+          }
+
+          if (&source != &widget2)
+          {
+            widget2.SetView(view);
+          }
+
+          if (&source != &widget3)
+          {
+            widget3.SetView(view);
+          }
+        }
+      }
+
+
+      void SynchronizeSlice(const LayeredSceneWidget& source,
+                            const SliceGeometry& slice,
+                            LayeredSceneWidget& widget1,
+                            LayeredSceneWidget& widget2,
+                            LayeredSceneWidget& widget3)
+      {
+        if (&source == &widget1 ||
+            &source == &widget2 ||
+            &source == &widget3)
+        {
+          if (&source != &widget1)
+          {
+            widget1.SetSlice(slice);
+          }
+
+          if (&source != &widget2)
+          {
+            widget2.SetSlice(slice);
+          }
+
+          if (&source != &widget3)
+          {
+            widget3.SetSlice(slice);
+          }
+        }
+      }
+
+
+      LayeredSceneWidget* CreateWidget()
+      {
+        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
+        widget->Register(dynamic_cast<WorldSceneWidget::IWorldObserver&>(*this));
+        widget->Register(dynamic_cast<LayeredSceneWidget::ISliceObserver&>(*this));
+        return widget.release();
+      }
+
+
+      void CreateLayout(BasicApplicationContext& context)
+      {
+        std::unique_ptr<OrthancStone::LayoutWidget> layout(new OrthancStone::LayoutWidget);
+        layout->SetBackgroundCleared(true);
+        //layout->SetBackgroundColor(255,0,0);
+        layout->SetPadding(5);
+
+        OrthancStone::LayoutWidget& layoutA = dynamic_cast<OrthancStone::LayoutWidget&>
+          (layout->AddWidget(new OrthancStone::LayoutWidget));
+        layoutA.SetPadding(0, 0, 0, 0, 5);
+        layoutA.SetVertical();
+        petAxial_ = &dynamic_cast<LayeredSceneWidget&>(layoutA.AddWidget(CreateWidget()));
+        OrthancStone::LayoutWidget& layoutA2 = dynamic_cast<OrthancStone::LayoutWidget&>
+          (layoutA.AddWidget(new OrthancStone::LayoutWidget));
+        layoutA2.SetPadding(0, 0, 0, 0, 5);
+        petSagittal_ = &dynamic_cast<LayeredSceneWidget&>(layoutA2.AddWidget(CreateWidget()));
+        petCoronal_ = &dynamic_cast<LayeredSceneWidget&>(layoutA2.AddWidget(CreateWidget()));
+
+        OrthancStone::LayoutWidget& layoutB = dynamic_cast<OrthancStone::LayoutWidget&>
+          (layout->AddWidget(new OrthancStone::LayoutWidget));
+        layoutB.SetPadding(0, 0, 0, 0, 5);
+        layoutB.SetVertical();
+        ctAxial_ = &dynamic_cast<LayeredSceneWidget&>(layoutB.AddWidget(CreateWidget()));
+        OrthancStone::LayoutWidget& layoutB2 = dynamic_cast<OrthancStone::LayoutWidget&>
+          (layoutB.AddWidget(new OrthancStone::LayoutWidget));
+        layoutB2.SetPadding(0, 0, 0, 0, 5);
+        ctSagittal_ = &dynamic_cast<LayeredSceneWidget&>(layoutB2.AddWidget(CreateWidget()));
+        ctCoronal_ = &dynamic_cast<LayeredSceneWidget&>(layoutB2.AddWidget(CreateWidget()));
+
+        OrthancStone::LayoutWidget& layoutC = dynamic_cast<OrthancStone::LayoutWidget&>
+          (layout->AddWidget(new OrthancStone::LayoutWidget));
+        layoutC.SetPadding(0, 0, 0, 0, 5);
+        layoutC.SetVertical();
+        fusionAxial_ = &dynamic_cast<LayeredSceneWidget&>(layoutC.AddWidget(CreateWidget()));
+        OrthancStone::LayoutWidget& layoutC2 = dynamic_cast<OrthancStone::LayoutWidget&>
+          (layoutC.AddWidget(new OrthancStone::LayoutWidget));
+        layoutC2.SetPadding(0, 0, 0, 0, 5);
+        fusionSagittal_ = &dynamic_cast<LayeredSceneWidget&>(layoutC2.AddWidget(CreateWidget()));
+        fusionCoronal_ = &dynamic_cast<LayeredSceneWidget&>(layoutC2.AddWidget(CreateWidget()));
+  
+        context.SetCentralWidget(layout.release());
+      }
+
+
+    public:
+      virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("ct", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the CT series")
+          ("pet", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the PET series")
+          ("rt", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the DICOM RT-STRUCT series (optional)")
+          ("threads", boost::program_options::value<unsigned int>()->default_value(3), 
+           "Number of download threads for the CT series")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(BasicApplicationContext& context,
+                              IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        processingEvent_ = true;
+
+        if (parameters.count("ct") != 1 ||
+            parameters.count("pet") != 1)
+        {
+          LOG(ERROR) << "The series ID is missing";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::string ct = parameters["ct"].as<std::string>();
+        std::string pet = parameters["pet"].as<std::string>();
+        unsigned int threads = parameters["threads"].as<unsigned int>();
+
+        VolumeImage& ctVolume = context.AddSeriesVolume(ct, true /* progressive download */, threads);
+        VolumeImage& petVolume = context.AddSeriesVolume(pet, true /* progressive download */, 1);
+
+        // Take the PET volume as the reference for the slices
+        interactorAxial_ = &dynamic_cast<Interactor&>
+          (context.AddInteractor(new Interactor(*this, petVolume, VolumeProjection_Axial, false)));
+        interactorCoronal_ = &dynamic_cast<Interactor&>
+          (context.AddInteractor(new Interactor(*this, petVolume, VolumeProjection_Coronal, false)));
+        interactorSagittal_ = &dynamic_cast<Interactor&>
+          (context.AddInteractor(new Interactor(*this, petVolume, VolumeProjection_Sagittal, true)));
+
+        CreateLayout(context);
+
+        AddLayer(*ctAxial_, ctVolume, true);
+        AddLayer(*ctCoronal_, ctVolume, true);
+        AddLayer(*ctSagittal_, ctVolume, true);
+
+        AddLayer(*petAxial_, petVolume, false);
+        AddLayer(*petCoronal_, petVolume, false);
+        AddLayer(*petSagittal_, petVolume, false);
+
+        AddLayer(*fusionAxial_, ctVolume, true);
+        AddLayer(*fusionAxial_, petVolume, false);
+        AddLayer(*fusionCoronal_, ctVolume, true);
+        AddLayer(*fusionCoronal_, petVolume, false);
+        AddLayer(*fusionSagittal_, ctVolume, true);
+        AddLayer(*fusionSagittal_, petVolume, false);
+
+        if (parameters.count("rt") == 1)
+        {
+          DicomStructureSet& rtStruct = context.AddStructureSet(parameters["rt"].as<std::string>());
+
+          Vector p = rtStruct.GetStructureCenter(0);
+          interactorAxial_->GetCursor().LookupSliceContainingPoint(p);
+
+          ctAxial_->AddLayer(new DicomStructureSetSlicer(rtStruct));
+          petAxial_->AddLayer(new DicomStructureSetSlicer(rtStruct));
+          fusionAxial_->AddLayer(new DicomStructureSetSlicer(rtStruct));
+        }        
+
+        ConnectSiblingLocations(*ctAxial_, *ctCoronal_, *ctSagittal_); 
+        ConnectSiblingLocations(*petAxial_, *petCoronal_, *petSagittal_); 
+        ConnectSiblingLocations(*fusionAxial_, *fusionCoronal_, *fusionSagittal_); 
+
+        interactorAxial_->AddWidget(*ctAxial_);
+        interactorAxial_->AddWidget(*petAxial_);
+        interactorAxial_->AddWidget(*fusionAxial_);
+        
+        interactorCoronal_->AddWidget(*ctCoronal_);
+        interactorCoronal_->AddWidget(*petCoronal_);
+        interactorCoronal_->AddWidget(*fusionCoronal_);
+        
+        interactorSagittal_->AddWidget(*ctSagittal_);
+        interactorSagittal_->AddWidget(*petSagittal_);
+        interactorSagittal_->AddWidget(*fusionSagittal_);
+
+        processingEvent_ = false;
+
+        statusBar.SetMessage("Use the key \"t\" to toggle the fullscreen mode");
+        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+      }
+
+      virtual void NotifySizeChange(const WorldSceneWidget& source,
+                                    ViewportGeometry& view)
+      {
+        view.FitContent();
+      }
+
+      virtual void NotifyViewChange(const WorldSceneWidget& source,
+                                    const ViewportGeometry& view)
+      {
+        if (!processingEvent_)  // Avoid reentrant calls
+        {
+          processingEvent_ = true;
+
+          SynchronizeView(source, view, *ctAxial_, *petAxial_, *fusionAxial_);
+          SynchronizeView(source, view, *ctCoronal_, *petCoronal_, *fusionCoronal_);
+          SynchronizeView(source, view, *ctSagittal_, *petSagittal_, *fusionSagittal_);
+          
+          processingEvent_ = false;
+        }
+      }
+
+      virtual void NotifySliceContentChange(const LayeredSceneWidget& source,
+                                     const SliceGeometry& slice)
+      {
+        if (!processingEvent_)  // Avoid reentrant calls
+        {
+          processingEvent_ = true;
+
+          SynchronizeSlice(source, slice, *ctAxial_, *petAxial_, *fusionAxial_);
+          SynchronizeSlice(source, slice, *ctCoronal_, *petCoronal_, *fusionCoronal_);
+          SynchronizeSlice(source, slice, *ctSagittal_, *petSagittal_, *fusionSagittal_);
+          
+          processingEvent_ = false;
+        }
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindow.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +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/>.
+ **/
+
+#include "SampleMainWindow.h"
+
+/**
+ * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
+ * this makes CMake unable to detect when the UI file changes.
+ **/
+#include <ui_SampleMainWindow.h>
+#include "../../../Applications/Samples/SampleApplicationBase.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+
+    SampleMainWindow::SampleMainWindow(
+      OrthancStone::NativeStoneApplicationContext& context,
+      OrthancStone::Samples::SampleSingleCanvasApplicationBase& stoneSampleApplication,
+      QWidget *parent) :
+      QStoneMainWindow(context, parent),
+      ui_(new Ui::SampleMainWindow),
+      stoneSampleApplication_(stoneSampleApplication)
+    {
+      ui_->setupUi(this);
+      SetCentralStoneWidget(*ui_->cairoCentralWidget);
+    }
+
+    SampleMainWindow::~SampleMainWindow()
+    {
+      delete ui_;
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindow.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,50 @@
+/**
+ * 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 "../../../Qt/QCairoWidget.h"
+#include "../../../Qt/QStoneMainWindow.h"
+
+namespace Ui 
+{
+  class SampleMainWindow;
+}
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+
+    class SampleSingleCanvasApplicationBase;
+
+    class SampleMainWindow : public QStoneMainWindow
+    {
+      Q_OBJECT
+
+    private:
+      Ui::SampleMainWindow*   ui_;
+      SampleSingleCanvasApplicationBase&  stoneSampleApplication_;
+
+    public:
+      explicit SampleMainWindow(OrthancStone::NativeStoneApplicationContext& context, SampleSingleCanvasApplicationBase& stoneSampleApplication, QWidget *parent = 0);
+      ~SampleMainWindow();
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindow.ui	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SampleMainWindow</class>
+ <widget class="QMainWindow" name="SampleMainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>903</width>
+    <height>634</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="baseSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Stone of Orthanc</string>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="layoutDirection">
+    <enum>Qt::LeftToRight</enum>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0">
+    <property name="sizeConstraint">
+     <enum>QLayout::SetDefaultConstraint</enum>
+    </property>
+    <item>
+     <widget class="QCairoWidget" name="cairoCentralWidget">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>500</height>
+       </size>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>903</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuTest">
+    <property name="title">
+     <string>Test</string>
+    </property>
+   </widget>
+   <addaction name="menuTest"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QCairoWidget</class>
+   <extends>QGraphicsView</extends>
+   <header location="global">QCairoWidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,96 @@
+/**
+ * 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 "SampleMainWindow.h"
+
+/**
+ * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
+ * this makes CMake unable to detect when the UI file changes.
+ **/
+#include <ui_SampleMainWindowWithButtons.h>
+#include "../../../Applications/Samples/SampleApplicationBase.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+
+    SampleMainWindowWithButtons::SampleMainWindowWithButtons(
+      OrthancStone::NativeStoneApplicationContext& context,
+      OrthancStone::Samples::SampleSingleCanvasWithButtonsApplicationBase& stoneSampleApplication,
+      QWidget *parent) :
+      QStoneMainWindow(context, parent),
+      ui_(new Ui::SampleMainWindowWithButtons),
+      stoneSampleApplication_(stoneSampleApplication)
+    {
+      ui_->setupUi(this);
+      SetCentralStoneWidget(*ui_->cairoCentralWidget);
+
+#if QT_VERSION >= 0x050000
+      connect(ui_->toolButton1, &QToolButton::clicked, this, &SampleMainWindowWithButtons::tool1Clicked);
+      connect(ui_->toolButton2, &QToolButton::clicked, this, &SampleMainWindowWithButtons::tool2Clicked);
+      connect(ui_->pushButton1, &QPushButton::clicked, this, &SampleMainWindowWithButtons::pushButton1Clicked);
+      connect(ui_->pushButton1, &QPushButton::clicked, this, &SampleMainWindowWithButtons::pushButton2Clicked);
+#else
+      connect(ui_->toolButton1, SIGNAL(clicked()), this, SLOT(tool1Clicked()));
+      connect(ui_->toolButton2, SIGNAL(clicked()), this, SLOT(tool2Clicked()));
+      connect(ui_->pushButton1, SIGNAL(clicked()), this, SLOT(pushButton1Clicked()));
+      connect(ui_->pushButton1, SIGNAL(clicked()), this, SLOT(pushButton2Clicked()));
+#endif
+
+      std::string pushButton1Name;
+      std::string pushButton2Name;
+      std::string tool1Name;
+      std::string tool2Name;
+      stoneSampleApplication_.GetButtonNames(pushButton1Name, pushButton2Name, tool1Name, tool2Name);
+
+      ui_->toolButton1->setText(QString::fromStdString(tool1Name));
+      ui_->toolButton2->setText(QString::fromStdString(tool2Name));
+      ui_->pushButton1->setText(QString::fromStdString(pushButton1Name));
+      ui_->pushButton2->setText(QString::fromStdString(pushButton2Name));
+    }
+
+    SampleMainWindowWithButtons::~SampleMainWindowWithButtons()
+    {
+      delete ui_;
+    }
+
+    void SampleMainWindowWithButtons::tool1Clicked()
+    {
+      stoneSampleApplication_.OnTool1Clicked();
+    }
+
+    void SampleMainWindowWithButtons::tool2Clicked()
+    {
+      stoneSampleApplication_.OnTool2Clicked();
+    }
+
+    void SampleMainWindowWithButtons::pushButton1Clicked()
+    {
+      stoneSampleApplication_.OnPushButton1Clicked();
+    }
+
+    void SampleMainWindowWithButtons::pushButton2Clicked()
+    {
+      stoneSampleApplication_.OnPushButton2Clicked();
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,56 @@
+/**
+ * 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 "../../../Qt/QCairoWidget.h"
+#include "../../../Qt/QStoneMainWindow.h"
+
+namespace Ui 
+{
+  class SampleMainWindowWithButtons;
+}
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+
+    class SampleSingleCanvasWithButtonsApplicationBase;
+
+    class SampleMainWindowWithButtons : public QStoneMainWindow
+    {
+      Q_OBJECT
+
+    private:
+      Ui::SampleMainWindowWithButtons*   ui_;
+      SampleSingleCanvasWithButtonsApplicationBase&  stoneSampleApplication_;
+
+    public:
+      explicit SampleMainWindowWithButtons(OrthancStone::NativeStoneApplicationContext& context, SampleSingleCanvasWithButtonsApplicationBase& stoneSampleApplication, QWidget *parent = 0);
+      ~SampleMainWindowWithButtons();
+
+    private slots:
+      void tool1Clicked();
+      void tool2Clicked();
+      void pushButton1Clicked();
+      void pushButton2Clicked();
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleMainWindowWithButtons.ui	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SampleMainWindowWithButtons</class>
+ <widget class="QMainWindow" name="SampleMainWindowWithButtons">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>903</width>
+    <height>634</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="baseSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Stone of Orthanc</string>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="layoutDirection">
+    <enum>Qt::LeftToRight</enum>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
+    <property name="sizeConstraint">
+     <enum>QLayout::SetDefaultConstraint</enum>
+    </property>
+    <item>
+     <widget class="QCairoWidget" name="cairoCentralWidget">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>500</height>
+       </size>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QGroupBox" name="horizontalGroupBox">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>100</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>16777215</width>
+        <height>100</height>
+       </size>
+      </property>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QToolButton" name="toolButton1">
+         <property name="text">
+          <string>tool1</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="toolButton2">
+         <property name="text">
+          <string>tool2</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButton1">
+         <property name="text">
+          <string>action1</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButton2">
+         <property name="text">
+          <string>action2</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>903</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuTest">
+    <property name="title">
+     <string>Test</string>
+    </property>
+   </widget>
+   <addaction name="menuTest"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QCairoWidget</class>
+   <extends>QGraphicsView</extends>
+   <header location="global">QCairoWidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Qt/SampleQtApplicationRunner.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,50 @@
+/**
+ * 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 "../../../Qt/QtStoneApplicationRunner.h"
+
+#if ORTHANC_ENABLE_QT != 1
+#error this file shall be included only with the ORTHANC_ENABLE_QT set to 1
+#endif
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SampleQtApplicationRunner : public OrthancStone::QtStoneApplicationRunner
+    {
+    protected:
+      virtual void InitializeMainWindow(OrthancStone::NativeStoneApplicationContext& context)
+      {
+        window_.reset(application_.CreateQtMainWindow());
+      }
+    public:
+      SampleQtApplicationRunner(MessageBroker& broker,
+                                SampleApplicationBase& application)
+        : OrthancStone::QtStoneApplicationRunner(broker, application)
+      {
+      }
+
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SampleApplicationBase.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,133 @@
+/**
+ * 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/IStoneApplication.h"
+#include "../../../Framework/Deprecated/Widgets/WorldSceneWidget.h"
+
+#if ORTHANC_ENABLE_WASM==1
+#include "../../../Platforms/Wasm/WasmPlatformApplicationAdapter.h"
+#include "../../../Platforms/Wasm/Defaults.h"
+#endif
+
+#if ORTHANC_ENABLE_QT==1
+#include "Qt/SampleMainWindow.h"
+#include "Qt/SampleMainWindowWithButtons.h"
+#endif
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SampleApplicationBase : public IStoneApplication
+    {
+    private:
+      boost::shared_ptr<Deprecated::IWidget>  mainWidget_;
+
+    public:
+      virtual void Initialize(StoneApplicationContext* context,
+                              Deprecated::IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE
+      {
+      }
+
+      virtual std::string GetTitle() const ORTHANC_OVERRIDE
+      {
+        return "Stone of Orthanc - Sample";
+      }
+
+      /**
+       * In the basic samples, the commands are handled by the platform adapter and NOT
+       * by the application handler
+      */
+      virtual void HandleSerializedMessage(const char* data) ORTHANC_OVERRIDE {};
+
+
+      virtual void Finalize() ORTHANC_OVERRIDE {}
+
+      virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) ORTHANC_OVERRIDE
+      {
+        mainWidget_ = widget;
+      }
+
+      virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() ORTHANC_OVERRIDE
+      {
+        return mainWidget_;
+      }
+
+#if ORTHANC_ENABLE_WASM==1
+      // default implementations for a single canvas named "canvas" in the HTML and an emtpy WasmApplicationAdapter
+
+      virtual void InitializeWasm() ORTHANC_OVERRIDE
+      {
+        AttachWidgetToWasmViewport("canvas", mainWidget_);
+      }
+
+      virtual WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(MessageBroker& broker)
+      {
+        return new WasmPlatformApplicationAdapter(broker, *this);
+      }
+#endif
+
+    };
+
+    // this application actually works in Qt and WASM
+    class SampleSingleCanvasWithButtonsApplicationBase : public SampleApplicationBase
+    {
+public:
+      virtual void OnPushButton1Clicked() {}
+      virtual void OnPushButton2Clicked() {}
+      virtual void OnTool1Clicked() {}
+      virtual void OnTool2Clicked() {}
+
+      virtual void GetButtonNames(std::string& pushButton1,
+                                  std::string& pushButton2,
+                                  std::string& tool1,
+                                  std::string& tool2
+                                  ) {
+        pushButton1 = "action1";
+        pushButton2 = "action2";
+        tool1 = "tool1";
+        tool2 = "tool2";
+      }
+
+#if ORTHANC_ENABLE_QT==1
+      virtual QStoneMainWindow* CreateQtMainWindow() {
+        return new SampleMainWindowWithButtons(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
+      }
+#endif
+
+    };
+
+    // this application actually works in SDL and WASM
+    class SampleSingleCanvasApplicationBase : public SampleApplicationBase
+    {
+public:
+
+#if ORTHANC_ENABLE_QT==1
+      virtual QStoneMainWindow* CreateQtMainWindow() {
+        return new SampleMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
+      }
+#endif
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SampleInteractor.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,131 @@
+/**
+ * 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 "SampleApplicationBase.h"
+
+#include "../../../Framework/Widgets/LayeredSceneWidget.h"
+#include "../../../Framework/Widgets/IWorldSceneInteractor.h"
+#include "../../../Framework/Toolbox/ParallelSlicesCursor.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    /**
+     * This is a basic mouse interactor for sample applications. It
+     * contains a set of parallel slices in the 3D space. The mouse
+     * wheel events make the widget change the slice that is
+     * displayed.
+     **/
+    class SampleInteractor : public IWorldSceneInteractor
+    {
+    private:
+      ParallelSlicesCursor   cursor_;
+
+    public:
+      SampleInteractor(VolumeImage& volume,
+                       VolumeProjection projection, 
+                       bool reverse)
+      {
+        std::unique_ptr<ParallelSlices> slices(volume.GetGeometry(projection, reverse));
+        cursor_.SetGeometry(*slices);
+      }
+
+      SampleInteractor(ISeriesLoader& series, 
+                       bool reverse)
+      {
+        if (reverse)
+        {
+          std::unique_ptr<ParallelSlices> slices(series.GetGeometry().Reverse());
+          cursor_.SetGeometry(*slices);
+        }
+        else
+        {
+          cursor_.SetGeometry(series.GetGeometry());
+        }
+      }
+
+      SampleInteractor(const ParallelSlices& slices)
+      {
+        cursor_.SetGeometry(slices);
+      }
+
+      ParallelSlicesCursor& GetCursor()
+      {
+        return cursor_;
+      }
+
+      void AddWidget(LayeredSceneWidget& widget)
+      {
+        widget.SetInteractor(*this);
+        widget.SetSlice(cursor_.GetCurrentSlice());
+      }
+
+      virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                          const ViewportGeometry& view,
+                                                          MouseButton button,
+                                                          double x,
+                                                          double y,
+                                                          IStatusBar* statusBar)
+      {
+        return NULL;
+      }
+
+      virtual void MouseOver(CairoContext& context,
+                             WorldSceneWidget& widget,
+                             const ViewportGeometry& view,
+                             double x,
+                             double y,
+                             IStatusBar* statusBar)
+      {
+      }
+
+      virtual void MouseWheel(WorldSceneWidget& widget,
+                              MouseWheelDirection direction,
+                              KeyboardModifiers modifiers,
+                              IStatusBar* statusBar)
+      {
+        if (cursor_.ApplyWheelEvent(direction, modifiers))
+        {
+          dynamic_cast<LayeredSceneWidget&>(widget).SetSlice(cursor_.GetCurrentSlice());
+        }
+      }
+
+      virtual void KeyPressed(WorldSceneWidget& widget,
+                              char key,
+                              KeyboardModifiers modifiers,
+                              IStatusBar* statusBar)
+      {
+      }
+
+      void LookupSliceContainingPoint(LayeredSceneWidget& widget,
+                                      const Vector& p)
+      {
+        if (cursor_.LookupSliceContainingPoint(p))
+        {
+          widget.SetSlice(cursor_.GetCurrentSlice());
+        }
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SampleList.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,41 @@
+// The macro "ORTHANC_STONE_SAMPLE" must be set by the CMake script
+
+#if ORTHANC_STONE_SAMPLE == 1
+#include "EmptyApplication.h"
+typedef OrthancStone::Samples::EmptyApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 2
+#include "TestPatternApplication.h"
+typedef OrthancStone::Samples::TestPatternApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 3
+#include "SingleFrameApplication.h"
+typedef OrthancStone::Samples::SingleFrameApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 4
+#include "SingleVolumeApplication.h"
+typedef OrthancStone::Samples::SingleVolumeApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 5
+#include "BasicPetCtFusionApplication.h"
+typedef OrthancStone::Samples::BasicPetCtFusionApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 6
+#include "SynchronizedSeriesApplication.h"
+typedef OrthancStone::Samples::SynchronizedSeriesApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 7
+#include "LayoutPetCtFusionApplication.h"
+typedef OrthancStone::Samples::LayoutPetCtFusionApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 8
+#include "SimpleViewerApplicationSingleFile.h"
+typedef OrthancStone::Samples::SimpleViewerApplication SampleApplication;
+
+#elif ORTHANC_STONE_SAMPLE == 9
+#include "SingleFrameEditorApplication.h"
+typedef OrthancStone::Samples::SingleFrameEditorApplication SampleApplication;
+
+#else
+#error Please set the ORTHANC_STONE_SAMPLE macro
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SampleMainNative.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,44 @@
+/**
+ * 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 "SampleList.h"
+#if ORTHANC_ENABLE_SDL==1
+#include "../../Sdl/SdlStoneApplicationRunner.h"
+#endif
+#if ORTHANC_ENABLE_QT==1
+#include "Qt/SampleQtApplicationRunner.h"
+#endif
+
+int main(int argc, char* argv[]) 
+{
+  boost::shared_ptr<SampleApplication> sampleStoneApplication(new SampleApplication);
+
+#if ORTHANC_ENABLE_SDL==1
+  OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(sampleStoneApplication);
+  return sdlApplicationRunner.Execute(argc, argv);
+#endif
+  
+#if ORTHANC_ENABLE_QT==1
+  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(sampleStoneApplication);
+  return qtAppRunner.Execute(argc, argv);
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SampleMainWasm.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,37 @@
+/**
+ * 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 "Platforms/Wasm/WasmWebService.h"
+#include "Platforms/Wasm/WasmViewport.h"
+
+#include <emscripten/emscripten.h>
+
+#include "SampleList.h"
+
+
+OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) 
+{
+  return new SampleApplication(broker);
+}
+
+OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, OrthancStone::IStoneApplication* application)
+{
+  return dynamic_cast<SampleApplication*>(application)->CreateWasmApplicationAdapter(broker);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Samples-status.md	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,103 @@
+Executable versions
+================
+Generic options
+----------------------
+```
+("help", "Display this help and exit")
+("verbose", "Be verbose in logs")
+("orthanc", boost::program_options::value<std::string>()
+  ->default_value("http://localhost:8042/"),
+  "URL to the Orthanc server")
+("username", "Username for the Orthanc server")
+("password", "Password for the Orthanc server")
+("https-verify", boost::program_options::value<bool>()
+  ->default_value(true), "Check HTTPS certificates")
+```
+OrthancStoneSimpleViewer
+-------------------------------------
+- Options:
+    ```
+    - "studyId", std::string, "Orthanc ID of the study"
+    ```
+- study loading works OK
+- Invert does not work:
+```
+void SimpleViewerApplication::ExecuteAction(SimpleViewerApplication::Actions action)
+  {
+    // TODO
+  }
+```
+
+OrthancStoneSimpleViewerSingleFile
+-------------------------------------
+- Options:
+    ```
+    - "studyId", std::string, "Orthanc ID of the study"
+    ```
+
+Study loading works.
+
+The `line` and `circle` buttons work and call this:
+```
+virtual void OnTool1Clicked()
+{
+  currentTool_ = Tools_LineMeasure;
+}
+
+virtual void OnTool2Clicked()
+{
+  currentTool_ = Tools_CircleMeasure;
+}
+```
+The `action1` and `action2` buttons are not connected
+
+The following is displayed in the console at launch time:
+```
+W0313 12:20:12.790449 NativeStoneApplicationRunner.cpp:55] Use the key "s" to reinitialize the layout
+W0313 12:20:12.790449 NativeStoneApplicationRunner.cpp:55] Use the key "n" to go to next image in the main viewport
+```
+However, when looking at `MainWidgetInteractor::KeyPressed` (`SimpleViewerApplicationSingleFile.h:169`), only the following is processed:
+- 's': reset layout
+- 'l': select line tool
+- 'c': select circle tool
+
+OrthancStoneSingleFrame
+-------------------------------------
+```
+generic.add_options()
+("instance", boost::program_options::value<std::string>(), 
+"Orthanc ID of the instance")
+("frame", boost::program_options::value<unsigned int>()
+  ->default_value(0),
+"Number of the frame, for multi-frame DICOM instances")
+("smooth", boost::program_options::value<bool>()
+  ->default_value(true), 
+"Enable bilinear interpolation to smooth the image");
+```
+only key handled in `KeyPressed` is `s` to call `widget.FitContent()`
+
+
+OrthancStoneSingleFrameEditor
+-------------------------------------
+```
+generic.add_options()
+("instance", boost::program_options::value<std::string>(),
+"Orthanc ID of the instance")
+("frame", boost::program_options::value<unsigned int>()
+  ->default_value(0),
+"Number of the frame, for multi-frame DICOM instances");
+```
+Available commands in `KeyPressed` (`SingleFrameEditorApplication.h:280`): 
+- 'a' widget.FitContent()
+- 'c' Crop tool
+- 'm' Mask tool
+- 'd' dump to json and diplay result (?)
+- 'e' export current view to Dicom with dummy tags (?)
+- 'i' wdiget.SwitchInvert
+- 't' Move tool
+- 'n' switch between nearest and bilinear interpolation
+- 'r' Rotate tool
+- 's' Resize tool
+- 'w' Windowing tool
+- 'ctrl+y' redo
+- 'ctrl+z' undo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/AppStatus.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <string>
+
+
+namespace SimpleViewer
+{
+  struct AppStatus
+  {
+    std::string patientId;
+    std::string studyDescription;
+    std::string currentInstanceIdInMainViewport;
+    // note: if you add members here, update the serialization code below and deserialization in simple-viewer.ts -> onAppStatusUpdated()
+
+
+    AppStatus()
+    {
+    }
+
+    void ToJson(Json::Value &output) const
+    {
+      output["patientId"] = patientId;
+      output["studyDescription"] = studyDescription;
+      output["currentInstanceIdInMainViewport"] = currentInstanceIdInMainViewport;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +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/>.
+ **/
+
+#include "MainWidgetInteractor.h"
+
+#include "SimpleViewerApplication.h"
+
+namespace SimpleViewer {
+
+  Deprecated::IWorldSceneMouseTracker* MainWidgetInteractor::CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                    const Deprecated::ViewportGeometry& view,
+                                                                    MouseButton button,
+                                                                    KeyboardModifiers modifiers,
+                                                                    int viewportX,
+                                                                    int viewportY,
+                                                                    double x,
+                                                                    double y,
+                                                                    Deprecated::IStatusBar* statusBar,
+                                                                    const std::vector<Deprecated::Touch>& displayTouches)
+  {
+    if (button == MouseButton_Left)
+    {
+      if (application_.GetCurrentTool() == Tool_LineMeasure)
+      {
+        return new Deprecated::LineMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
+                                      x, y, 255, 0, 0, application_.GetFont());
+      }
+      else if (application_.GetCurrentTool() == Tool_CircleMeasure)
+      {
+        return new Deprecated::CircleMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
+                                        x, y, 255, 0, 0, application_.GetFont());
+      }
+      else if (application_.GetCurrentTool() == Tool_Crop)
+      {
+        // TODO
+      }
+      else if (application_.GetCurrentTool() == Tool_Windowing)
+      {
+        // TODO
+      }
+      else if (application_.GetCurrentTool() == Tool_Zoom)
+      {
+        // TODO
+      }
+      else if (application_.GetCurrentTool() == Tool_Pan)
+      {
+        // TODO
+      }
+    }
+    return NULL;
+  }
+
+  void MainWidgetInteractor::MouseOver(CairoContext& context,
+                                       Deprecated::WorldSceneWidget& widget,
+                                       const Deprecated::ViewportGeometry& view,
+                                       double x,
+                                       double y,
+                                       Deprecated::IStatusBar* statusBar)
+  {
+    if (statusBar != NULL)
+    {
+      Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+
+      char buf[64];
+      sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
+              p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+      statusBar->SetMessage(buf);
+    }
+  }
+
+  void MainWidgetInteractor::MouseWheel(Deprecated::WorldSceneWidget& widget,
+                                        MouseWheelDirection direction,
+                                        KeyboardModifiers modifiers,
+                                        Deprecated::IStatusBar* statusBar)
+  {
+  }
+
+  void MainWidgetInteractor::KeyPressed(Deprecated::WorldSceneWidget& widget,
+                                        KeyboardKeys key,
+                                        char keyChar,
+                                        KeyboardModifiers modifiers,
+                                        Deprecated::IStatusBar* statusBar)
+  {
+    switch (keyChar)
+    {
+    case 's':
+      widget.FitContent();
+      break;
+
+    default:
+      break;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/MainWidgetInteractor.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,76 @@
+/**
+ * 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/Deprecated/Widgets/IWorldSceneInteractor.h"
+
+using namespace OrthancStone;
+
+namespace SimpleViewer {
+
+  class SimpleViewerApplication;
+
+  class MainWidgetInteractor : public Deprecated::IWorldSceneInteractor
+  {
+  private:
+    SimpleViewerApplication&  application_;
+
+  public:
+    MainWidgetInteractor(SimpleViewerApplication&  application) :
+      application_(application)
+    {
+    }
+
+    /**
+        WorldSceneWidget: 
+    */
+    virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                    const Deprecated::ViewportGeometry& view,
+                                                                    MouseButton button,
+                                                                    KeyboardModifiers modifiers,
+                                                                    int viewportX,
+                                                                    int viewportY,
+                                                                    double x,
+                                                                    double y,
+                                                                    Deprecated::IStatusBar* statusBar,
+                                                                    const std::vector<Deprecated::Touch>& displayTouches);
+
+    virtual void MouseOver(CairoContext& context,
+                           Deprecated::WorldSceneWidget& widget,
+                           const Deprecated::ViewportGeometry& view,
+                           double x,
+                           double y,
+                           Deprecated::IStatusBar* statusBar);
+
+    virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
+                            MouseWheelDirection direction,
+                            KeyboardModifiers modifiers,
+                            Deprecated::IStatusBar* statusBar);
+
+    virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
+                            KeyboardKeys key,
+                            char keyChar,
+                            KeyboardModifiers modifiers,
+                            Deprecated::IStatusBar* statusBar);
+  };
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,109 @@
+/**
+ * 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 "SimpleViewerMainWindow.h"
+
+/**
+ * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as
+ * this makes CMake unable to detect when the UI file changes.
+ **/
+#include <ui_SimpleViewerMainWindow.h>
+#include "../../SimpleViewerApplication.h"
+
+
+namespace SimpleViewer
+{
+  template<typename T, typename U>
+  bool ExecuteCommand(U* handler, const T& command)
+  {
+    std::string serializedCommand = StoneSerialize(command);
+    StoneDispatchToHandler(serializedCommand, handler);
+  }
+
+  SimpleViewerMainWindow::SimpleViewerMainWindow(
+    OrthancStone::NativeStoneApplicationContext& context,
+    SimpleViewerApplication& stoneApplication,
+    QWidget *parent) :
+    QStoneMainWindow(context, parent),
+    ui_(new Ui::SimpleViewerMainWindow),
+    stoneApplication_(stoneApplication)
+  {
+    ui_->setupUi(this);
+    SetCentralStoneWidget(*ui_->cairoCentralWidget);
+
+#if QT_VERSION >= 0x050000
+    connect(ui_->toolButtonCrop, &QToolButton::clicked, this, &SimpleViewerMainWindow::cropClicked);
+    connect(ui_->pushButtonUndoCrop, &QToolButton::clicked, this, &SimpleViewerMainWindow::undoCropClicked);
+    connect(ui_->toolButtonLine, &QToolButton::clicked, this, &SimpleViewerMainWindow::lineClicked);
+    connect(ui_->toolButtonCircle, &QToolButton::clicked, this, &SimpleViewerMainWindow::circleClicked);
+    connect(ui_->toolButtonWindowing, &QToolButton::clicked, this, &SimpleViewerMainWindow::windowingClicked);
+    connect(ui_->pushButtonRotate, &QPushButton::clicked, this, &SimpleViewerMainWindow::rotateClicked);
+    connect(ui_->pushButtonInvert, &QPushButton::clicked, this, &SimpleViewerMainWindow::invertClicked);
+#else
+    connect(ui_->toolButtonCrop, SIGNAL(clicked()), this, SLOT(cropClicked()));
+    connect(ui_->toolButtonLine, SIGNAL(clicked()), this, SLOT(lineClicked()));
+    connect(ui_->toolButtonCircle, SIGNAL(clicked()), this, SLOT(circleClicked()));
+    connect(ui_->toolButtonWindowing, SIGNAL(clicked()), this, SLOT(windowingClicked()));
+    connect(ui_->pushButtonUndoCrop, SIGNAL(clicked()), this, SLOT(undoCropClicked()));
+    connect(ui_->pushButtonRotate, SIGNAL(clicked()), this, SLOT(rotateClicked()));
+    connect(ui_->pushButtonInvert, SIGNAL(clicked()), this, SLOT(invertClicked()));
+#endif
+  }
+
+  SimpleViewerMainWindow::~SimpleViewerMainWindow()
+  {
+    delete ui_;
+  }
+
+  void SimpleViewerMainWindow::cropClicked()
+  {
+    stoneApplication_.ExecuteCommand(SelectTool(Tool_Crop));
+  }
+
+  void SimpleViewerMainWindow::undoCropClicked()
+  {
+    stoneApplication_.ExecuteCommand(Action(ActionType_UndoCrop));
+  }
+
+  void SimpleViewerMainWindow::lineClicked()
+  {
+    stoneApplication_.ExecuteCommand(SelectTool(Tool_LineMeasure));
+  }
+
+  void SimpleViewerMainWindow::circleClicked()
+  {
+    stoneApplication_.ExecuteCommand(SelectTool(Tool_CircleMeasure));
+  }
+
+  void SimpleViewerMainWindow::windowingClicked()
+  {
+    stoneApplication_.ExecuteCommand(SelectTool(Tool_Windowing));
+  }
+
+  void SimpleViewerMainWindow::rotateClicked()
+  {
+    stoneApplication_.ExecuteCommand(Action(ActionType_Rotate));
+  }
+
+  void SimpleViewerMainWindow::invertClicked()
+  {
+    stoneApplication_.ExecuteCommand(Action(ActionType_Invert));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,57 @@
+/**
+ * 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/Qt/QCairoWidget.h>
+#include <Applications/Qt/QStoneMainWindow.h>
+
+namespace Ui 
+{
+  class SimpleViewerMainWindow;
+}
+
+using namespace OrthancStone;
+
+namespace SimpleViewer
+{
+  class SimpleViewerApplication;
+
+  class SimpleViewerMainWindow : public QStoneMainWindow
+  {
+    Q_OBJECT
+
+  private:
+    Ui::SimpleViewerMainWindow*   ui_;
+    SimpleViewerApplication&      stoneApplication_;
+
+  public:
+    explicit SimpleViewerMainWindow(OrthancStone::NativeStoneApplicationContext& context, SimpleViewerApplication& stoneApplication, QWidget *parent = 0);
+    ~SimpleViewerMainWindow();
+
+  private slots:
+    void cropClicked();
+    void undoCropClicked();
+    void rotateClicked();
+    void windowingClicked();
+    void lineClicked();
+    void circleClicked();
+    void invertClicked();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/SimpleViewerMainWindow.ui	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SimpleViewerMainWindow</class>
+ <widget class="QMainWindow" name="SimpleViewerMainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>903</width>
+    <height>634</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="baseSize">
+   <size>
+    <width>500</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Stone of Orthanc</string>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+     <horstretch>0</horstretch>
+     <verstretch>0</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="layoutDirection">
+    <enum>Qt::LeftToRight</enum>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
+    <property name="sizeConstraint">
+     <enum>QLayout::SetDefaultConstraint</enum>
+    </property>
+    <item>
+     <widget class="QCairoWidget" name="cairoCentralWidget">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>500</height>
+       </size>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QGroupBox" name="horizontalGroupBox">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>100</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>16777215</width>
+        <height>100</height>
+       </size>
+      </property>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QToolButton" name="toolButtonWindowing">
+         <property name="text">
+          <string>windowing</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="toolButtonCrop">
+         <property name="text">
+          <string>crop</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButtonUndoCrop">
+         <property name="text">
+          <string>undo crop</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="toolButtonLine">
+         <property name="text">
+          <string>line</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="toolButtonCircle">
+         <property name="text">
+          <string>circle</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButtonRotate">
+         <property name="text">
+          <string>rotate</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButtonInvert">
+         <property name="text">
+          <string>invert</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>903</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuTest">
+    <property name="title">
+     <string>Test</string>
+    </property>
+   </widget>
+   <addaction name="menuTest"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QCairoWidget</class>
+   <extends>QGraphicsView</extends>
+   <header location="global">QCairoWidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Qt/mainQt.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,14 @@
+#include "Applications/Qt/QtStoneApplicationRunner.h"
+
+#include "../../SimpleViewerApplication.h"
+#include "Framework/Messages/MessageBroker.h"
+
+
+int main(int argc, char* argv[]) 
+{
+  OrthancStone::MessageBroker broker;
+  SimpleViewer::SimpleViewerApplication stoneApplication(broker);
+
+  OrthancStone::QtStoneApplicationRunner qtAppRunner(broker, stoneApplication);
+  return qtAppRunner.Execute(argc, argv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,225 @@
+/**
+ * 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 "SimpleViewerApplication.h"
+
+#if ORTHANC_ENABLE_QT == 1
+#  include "Qt/SimpleViewerMainWindow.h"
+#endif
+
+#if ORTHANC_ENABLE_WASM == 1
+#  include <Platforms/Wasm/WasmViewport.h>
+#endif
+
+namespace SimpleViewer
+{
+
+  void SimpleViewerApplication::Initialize(StoneApplicationContext* context,
+                                           Deprecated::IStatusBar& statusBar,
+                                           const boost::program_options::variables_map& parameters)
+  {
+    context_ = context;
+    statusBar_ = &statusBar;
+
+    {// initialize viewports and layout
+      mainLayout_ = new Deprecated::LayoutWidget("main-layout");
+      mainLayout_->SetPadding(10);
+      mainLayout_->SetBackgroundCleared(true);
+      mainLayout_->SetBackgroundColor(0, 0, 0);
+      mainLayout_->SetHorizontal();
+
+      thumbnailsLayout_ = new Deprecated::LayoutWidget("thumbnail-layout");
+      thumbnailsLayout_->SetPadding(10);
+      thumbnailsLayout_->SetBackgroundCleared(true);
+      thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
+      thumbnailsLayout_->SetVertical();
+
+      mainWidget_ = new Deprecated::SliceViewerWidget(IObserver::GetBroker(), "main-viewport");
+      //mainWidget_->RegisterObserver(*this);
+
+      // hierarchy
+      mainLayout_->AddWidget(thumbnailsLayout_);
+      mainLayout_->AddWidget(mainWidget_);
+
+      // sources
+      smartLoader_.reset(new Deprecated::SmartLoader(IObserver::GetBroker(), context->GetOrthancApiClient()));
+      smartLoader_->SetImageQuality(Deprecated::SliceImageQuality_FullPam);
+
+      mainLayout_->SetTransmitMouseOver(true);
+      mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
+      mainWidget_->SetInteractor(*mainWidgetInteractor_);
+      thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
+    }
+
+    statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+    statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport");
+
+
+    if (parameters.count("studyId") < 1)
+    {
+      LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
+      context->GetOrthancApiClient().GetJsonAsync("/studies", new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyListReceived));
+    }
+    else
+    {
+      SelectStudy(parameters["studyId"].as<std::string>());
+    }
+  }
+
+
+  void SimpleViewerApplication::DeclareStartupOptions(boost::program_options::options_description& options)
+  {
+    boost::program_options::options_description generic("Sample options");
+    generic.add_options()
+        ("studyId", boost::program_options::value<std::string>(),
+         "Orthanc ID of the study")
+        ;
+
+    options.add(generic);
+  }
+
+  void SimpleViewerApplication::OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& response = message.GetJson();
+
+    if (response.isArray() &&
+        response.size() >= 1)
+    {
+      SelectStudy(response[0].asString());
+    }
+  }
+  void SimpleViewerApplication::OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& response = message.GetJson();
+
+    if (response.isObject() && response["Series"].isArray())
+    {
+      for (size_t i=0; i < response["Series"].size(); i++)
+      {
+        context_->GetOrthancApiClient().GetJsonAsync("/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnSeriesReceived));
+      }
+    }
+  }
+
+  void SimpleViewerApplication::OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& response = message.GetJson();
+
+    if (response.isObject() &&
+        response["Instances"].isArray() &&
+        response["Instances"].size() > 0)
+    {
+      // keep track of all instances IDs
+      const std::string& seriesId = response["ID"].asString();
+      seriesTags_[seriesId] = response;
+      instancesIdsPerSeriesId_[seriesId] = std::vector<std::string>();
+      for (size_t i = 0; i < response["Instances"].size(); i++)
+      {
+        const std::string& instanceId = response["Instances"][static_cast<int>(i)].asString();
+        instancesIdsPerSeriesId_[seriesId].push_back(instanceId);
+      }
+
+      // load the first instance in the thumbnail
+      LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
+
+      // if this is the first thumbnail loaded, load the first instance in the mainWidget
+      if (mainWidget_->GetLayerCount() == 0)
+      {
+        smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
+      }
+    }
+  }
+
+  void SimpleViewerApplication::LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
+  {
+    LOG(INFO) << "Loading thumbnail for series " << seriesId;
+    
+    Deprecated::SliceViewerWidget* thumbnailWidget = 
+      new Deprecated::SliceViewerWidget(IObserver::GetBroker(), "thumbnail-series-" + seriesId);
+    thumbnails_.push_back(thumbnailWidget);
+    thumbnailsLayout_->AddWidget(thumbnailWidget);
+    
+    thumbnailWidget->RegisterObserverCallback(
+      new Callable<SimpleViewerApplication, Deprecated::SliceViewerWidget::GeometryChangedMessage>
+      (*this, &SimpleViewerApplication::OnWidgetGeometryChanged));
+    
+    smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
+    thumbnailWidget->SetInteractor(*thumbnailInteractor_);
+  }
+
+  void SimpleViewerApplication::SelectStudy(const std::string& studyId)
+  {
+    context_->GetOrthancApiClient().GetJsonAsync("/studies/" + studyId, new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyReceived));
+  }
+
+  void SimpleViewerApplication::OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
+  {
+    // TODO: The "const_cast" could probably be replaced by "mainWidget_"
+    const_cast<Deprecated::SliceViewerWidget&>(message.GetOrigin()).FitContent();
+  }
+
+  void SimpleViewerApplication::SelectSeriesInMainViewport(const std::string& seriesId)
+  {
+    smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
+  }
+
+  bool SimpleViewerApplication::Handle(const StoneSampleCommands::SelectTool& value)
+  {
+    currentTool_ = value.tool;
+    return true;
+  }
+
+  bool SimpleViewerApplication::Handle(const StoneSampleCommands::Action& value)
+  {
+    switch (value.type)
+    {
+    case ActionType_Invert:
+      // TODO
+      break;
+    case ActionType_UndoCrop:
+      // TODO
+      break;
+    case ActionType_Rotate:
+      // TODO
+      break;
+    default:
+      throw std::runtime_error("Action type not supported");
+    }
+    return true;
+  }
+
+#if ORTHANC_ENABLE_QT==1
+  QStoneMainWindow* SimpleViewerApplication::CreateQtMainWindow()
+  {
+    return new SimpleViewerMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
+  }
+#endif
+
+#if ORTHANC_ENABLE_WASM==1
+  void SimpleViewerApplication::InitializeWasm() {
+
+    AttachWidgetToWasmViewport("canvasThumbnails", thumbnailsLayout_);
+    AttachWidgetToWasmViewport("canvasMain", mainWidget_);
+  }
+#endif
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/SimpleViewerApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,175 @@
+/**
+ * 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
+
+ /*
+ This header contains the command definitions for the sample applications
+ */
+#include "Applications/Samples/StoneSampleCommands_generated.hpp"
+using namespace StoneSampleCommands;
+
+#include "Applications/IStoneApplication.h"
+
+#include "../../../../Framework/Deprecated/Layers/CircleMeasureTracker.h"
+#include "../../../../Framework/Deprecated/Layers/LineMeasureTracker.h"
+#include "../../../../Framework/Deprecated/SmartLoader.h"
+#include "../../../../Framework/Deprecated/Widgets/LayoutWidget.h"
+#include "../../../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
+#include "../../../../Framework/Messages/IObserver.h"
+
+#if ORTHANC_ENABLE_WASM==1
+#include "Platforms/Wasm/WasmPlatformApplicationAdapter.h"
+#include "Platforms/Wasm/Defaults.h"
+#endif
+
+#if ORTHANC_ENABLE_QT==1
+#include "Qt/SimpleViewerMainWindow.h"
+#endif
+
+#include <Core/Images/Font.h>
+#include <Core/Logging.h>
+
+#include "ThumbnailInteractor.h"
+#include "MainWidgetInteractor.h"
+#include "AppStatus.h"
+
+using namespace OrthancStone;
+
+
+namespace SimpleViewer
+{
+
+  class SimpleViewerApplication
+    : public IStoneApplication
+    , public IObserver
+    , public IObservable
+    , public StoneSampleCommands::IHandler
+  {
+  public:
+
+    struct StatusUpdatedMessage : public IMessage
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
+      const AppStatus& status_;
+
+      StatusUpdatedMessage(const AppStatus& status)
+        : status_(status)
+      {
+      }
+    };
+
+  private:
+    Tool                                currentTool_;
+
+    std::unique_ptr<MainWidgetInteractor> mainWidgetInteractor_;
+    std::unique_ptr<ThumbnailInteractor>  thumbnailInteractor_;
+    Deprecated::LayoutWidget*                       mainLayout_;
+    Deprecated::LayoutWidget*                       thumbnailsLayout_;
+    Deprecated::SliceViewerWidget*                  mainWidget_;
+    std::vector<Deprecated::SliceViewerWidget*>     thumbnails_;
+    std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
+    std::map<std::string, Json::Value>  seriesTags_;
+    unsigned int                        currentInstanceIndex_;
+    Deprecated::WidgetViewport*       wasmViewport1_;
+    Deprecated::WidgetViewport*       wasmViewport2_;
+
+    Deprecated::IStatusBar*                         statusBar_;
+    std::unique_ptr<Deprecated::SmartLoader>          smartLoader_;
+
+    Orthanc::Font                       font_;
+
+  public:
+    SimpleViewerApplication(MessageBroker& broker) :
+      IObserver(broker),
+      IObservable(broker),
+      currentTool_(StoneSampleCommands::Tool_LineMeasure),
+      mainLayout_(NULL),
+      currentInstanceIndex_(0),
+      wasmViewport1_(NULL),
+      wasmViewport2_(NULL)
+    {
+      font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
+    }
+
+    virtual void Finalize() ORTHANC_OVERRIDE {}
+    virtual Deprecated::IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainLayout_;}
+
+    virtual void DeclareStartupOptions(boost::program_options::options_description& options) ORTHANC_OVERRIDE;
+    virtual void Initialize(StoneApplicationContext* context,
+                            Deprecated::IStatusBar& statusBar,
+                            const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE;
+
+    void OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId);
+
+    void SelectStudy(const std::string& studyId);
+
+    void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message);
+
+    void SelectSeriesInMainViewport(const std::string& seriesId);
+
+
+    Tool GetCurrentTool() const
+    {
+      return currentTool_;
+    }
+
+    const Orthanc::Font& GetFont() const
+    {
+      return font_;
+    }
+
+    // ExecuteAction method was empty (its body was a single "TODO" comment)
+    virtual bool Handle(const SelectTool& value) ORTHANC_OVERRIDE;
+    virtual bool Handle(const Action& value) ORTHANC_OVERRIDE;
+
+    template<typename T>
+    bool ExecuteCommand(const T& cmd)
+    {
+      std::string cmdStr = StoneSampleCommands::StoneSerialize(cmd);
+      return StoneSampleCommands::StoneDispatchToHandler(cmdStr, this);
+    }
+
+    virtual void HandleSerializedMessage(const char* data) ORTHANC_OVERRIDE
+    {
+      StoneSampleCommands::StoneDispatchToHandler(data, this);
+    }
+
+    virtual std::string GetTitle() const ORTHANC_OVERRIDE {return "SimpleViewer";}
+
+#if ORTHANC_ENABLE_WASM==1
+    virtual void InitializeWasm() ORTHANC_OVERRIDE;
+#endif
+
+#if ORTHANC_ENABLE_QT==1
+    virtual QStoneMainWindow* CreateQtMainWindow();
+#endif
+  };
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,46 @@
+/**
+ * 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 "ThumbnailInteractor.h"
+
+#include "SimpleViewerApplication.h"
+
+namespace SimpleViewer {
+
+  Deprecated::IWorldSceneMouseTracker* ThumbnailInteractor::CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                   const Deprecated::ViewportGeometry& view,
+                                                                   MouseButton button,
+                                                                   KeyboardModifiers modifiers,
+                                                                   int viewportX,
+                                                                   int viewportY,
+                                                                   double x,
+                                                                   double y,
+                                                                   Deprecated::IStatusBar* statusBar,
+                                                                   const std::vector<Deprecated::Touch>& displayTouches)
+  {
+    if (button == MouseButton_Left)
+    {
+      statusBar->SetMessage("selected thumbnail " + widget.GetName());
+      std::string seriesId = widget.GetName().substr(strlen("thumbnail-series-"));
+      application_.SelectSeriesInMainViewport(seriesId);
+    }
+    return NULL;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/ThumbnailInteractor.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,77 @@
+/**
+ * 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/Deprecated/Widgets/IWorldSceneInteractor.h"
+
+using namespace OrthancStone;
+
+namespace SimpleViewer {
+
+  class SimpleViewerApplication;
+
+  class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
+  {
+  private:
+    SimpleViewerApplication&  application_;
+  public:
+    ThumbnailInteractor(SimpleViewerApplication&  application) :
+      application_(application)
+    {
+    }
+
+    virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                    const Deprecated::ViewportGeometry& view,
+                                                                    MouseButton button,
+                                                                    KeyboardModifiers modifiers,
+                                                                    int viewportX,
+                                                                    int viewportY,
+                                                                    double x,
+                                                                    double y,
+                                                                    Deprecated::IStatusBar* statusBar,
+                                                                    const std::vector<Deprecated::Touch>& displayTouches);
+
+    virtual void MouseOver(CairoContext& context,
+                           Deprecated::WorldSceneWidget& widget,
+                           const Deprecated::ViewportGeometry& view,
+                           double x,
+                           double y,
+                           Deprecated::IStatusBar* statusBar)
+    {}
+
+    virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
+                            MouseWheelDirection direction,
+                            KeyboardModifiers modifiers,
+                            Deprecated::IStatusBar* statusBar)
+    {}
+
+    virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
+                            KeyboardKeys key,
+                            char keyChar,
+                            KeyboardModifiers modifiers,
+                            Deprecated::IStatusBar* statusBar)
+    {}
+
+  };
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,51 @@
+/**
+ * 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 "SimpleViewerWasmApplicationAdapter.h"
+
+namespace SimpleViewer
+{
+
+  SimpleViewerWasmApplicationAdapter::SimpleViewerWasmApplicationAdapter(MessageBroker &broker, SimpleViewerApplication &application)
+      : WasmPlatformApplicationAdapter(broker, application),
+        viewerApplication_(application)
+  {
+    application.RegisterObserverCallback(new Callable<SimpleViewerWasmApplicationAdapter, SimpleViewerApplication::StatusUpdatedMessage>(*this, &SimpleViewerWasmApplicationAdapter::OnStatusUpdated));
+  }
+
+  void SimpleViewerWasmApplicationAdapter::OnStatusUpdated(const SimpleViewerApplication::StatusUpdatedMessage &message)
+  {
+    Json::Value statusJson;
+    message.status_.ToJson(statusJson);
+
+    Json::Value event;
+    event["event"] = "appStatusUpdated";
+    event["data"] = statusJson;
+
+    Json::StreamWriterBuilder builder;
+    std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
+    std::ostringstream outputStr;
+
+    writer->write(event, &outputStr);
+
+    NotifyStatusUpdateFromCppToWebWithString(outputStr.str());
+  }
+
+} // namespace SimpleViewer
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,43 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#pragma once
+
+#include <string>
+#include <Framework/Messages/IObserver.h>
+#include <Platforms/Wasm/WasmPlatformApplicationAdapter.h>
+
+#include "../../SimpleViewerApplication.h"
+
+namespace SimpleViewer {
+
+  class SimpleViewerWasmApplicationAdapter : public WasmPlatformApplicationAdapter
+    {
+      SimpleViewerApplication&  viewerApplication_;
+
+    public:
+      SimpleViewerWasmApplicationAdapter(MessageBroker& broker, SimpleViewerApplication& application);
+
+    private:
+      void OnStatusUpdated(const SimpleViewerApplication::StatusUpdatedMessage& message);
+
+    };
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/mainWasm.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,38 @@
+/**
+ * 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 "Platforms/Wasm/WasmWebService.h"
+#include "Platforms/Wasm/WasmViewport.h"
+
+#include <emscripten/emscripten.h>
+
+#include "../../SimpleViewerApplication.h"
+#include "SimpleViewerWasmApplicationAdapter.h"
+
+
+OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) {
+  
+  return new SimpleViewer::SimpleViewerApplication(broker);
+}
+
+OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, IStoneApplication* application)
+{
+  return new SimpleViewer::SimpleViewerWasmApplicationAdapter(broker, *(dynamic_cast<SimpleViewer::SimpleViewerApplication*>(application)));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,43 @@
+<!doctype html>
+
+<html lang="us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+    <!-- Disable pinch zoom on mobile devices -->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="HandheldFriendly" content="true" />
+
+    <title>Simple Viewer</title>
+    <link href="styles.css" rel="stylesheet" />
+
+<body>
+  <div id="breadcrumb">
+    <span id="label-patient-id"></span>
+    <span id="label-study-description"></span>
+    <span id="label-series-description"></span>
+  </div>
+  <div style="height: calc(100% - 50px)">
+    <div style="width: 20%; height: 100%; display: inline-block">
+      <canvas id="canvasThumbnails"></canvas>
+    </div>
+    <div style="width: 70%; height: 100%; display: inline-block">
+      <canvas id="canvasMain"></canvas>
+    </div>
+  </div>
+  <div id="toolbox" style="height: 50px">
+    <button tool-selector="line-measure" class="tool-selector">line</button>
+    <button tool-selector="circle-measure" class="tool-selector">circle</button>
+    <button tool-selector="crop" class="tool-selector">crop</button>
+    <button tool-selector="windowing" class="tool-selector">windowing</button>
+    <button tool-selector="zoom" class="tool-selector">zoom</button>
+    <button tool-selector="pan" class="tool-selector">pan</button>
+    <button action-trigger="rotate-left" class="action-trigger">rotate left</button>
+    <button action-trigger="rotate-right" class="action-trigger">rotate right</button>
+    <button action-trigger="invert" class="action-trigger">invert</button>
+  </div>
+  <script type="text/javascript" src="app-simple-viewer.js"></script>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/simple-viewer.ts	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,81 @@
+import wasmApplicationRunner = require('../../../../Platforms/Wasm/wasm-application-runner');
+
+wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSimpleViewer", "/orthanc");
+
+function SelectTool(toolName: string) {
+  var command = {
+    command: "selectTool:" + toolName,
+    commandType: "generic-no-arg-command",
+    args: {
+    }                                                                                                                       
+  };
+  wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
+}
+
+function PerformAction(actionName: string) {
+  var command = {
+    command: "action:" + actionName,
+    commandType: "generic-no-arg-command",
+    args: {
+    }
+  };
+  wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
+}
+
+class SimpleViewerUI {
+
+  private _labelPatientId: HTMLSpanElement;
+  private _labelStudyDescription: HTMLSpanElement;
+
+  public constructor() {
+    // install "SelectTool" handlers
+    document.querySelectorAll("[tool-selector]").forEach((e) => {
+      (e as HTMLButtonElement).addEventListener("click", () => {
+        SelectTool(e.attributes["tool-selector"].value);
+      });
+    });
+
+    // install "PerformAction" handlers
+    document.querySelectorAll("[action-trigger]").forEach((e) => {
+      (e as HTMLButtonElement).addEventListener("click", () => {
+        PerformAction(e.attributes["action-trigger"].value);
+      });
+    });
+
+    // connect all ui elements to members
+    this._labelPatientId = document.getElementById("label-patient-id") as HTMLSpanElement;
+    this._labelStudyDescription = document.getElementById("label-study-description") as HTMLSpanElement;
+  }
+
+  public onAppStatusUpdated(status: any) {
+    this._labelPatientId.innerText = status["patientId"];
+    this._labelStudyDescription.innerText = status["studyDescription"];
+    // this.highlighThumbnail(status["currentInstanceIdInMainViewport"]);
+  }
+
+}
+
+var ui = new SimpleViewerUI();
+
+// this method is called "from the C++ code" when the StoneApplication is updated.
+// it can be used to update the UI of the application
+function UpdateWebApplicationWithString(statusUpdateMessageString: string) {
+  console.log("updating web application with string: ", statusUpdateMessageString);
+  let statusUpdateMessage = JSON.parse(statusUpdateMessageString);
+
+  if ("event" in statusUpdateMessage) {
+    let eventName = statusUpdateMessage["event"];
+    if (eventName == "appStatusUpdated") {
+      ui.onAppStatusUpdated(statusUpdateMessage["data"]);
+    }
+  }
+}
+
+function UpdateWebApplicationWithSerializedMessage(statusUpdateMessageString: string) {
+  console.log("updating web application with serialized message: ", statusUpdateMessageString);
+  console.log("<not supported in the simple viewer!>");
+}
+
+// make it available to other js scripts in the application
+(<any> window).UpdateWebApplicationWithString = UpdateWebApplicationWithString;
+(<any> window).UpdateWebApplicationWithSerializedMessage = UpdateWebApplicationWithSerializedMessage;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/styles.css	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,54 @@
+html, body {
+    width: 100%;
+    height: 100%;
+    margin: 0px;
+    border: 0;
+    overflow: hidden; /*  Disable scrollbars */
+    display: block;  /* No floating content on sides */
+    background-color: black;
+    color: white;
+    font-family: Arial, Helvetica, sans-serif;
+}
+
+canvas {
+    left:0px;
+    top:0px;
+}
+
+#canvas-group {
+    padding:5px;
+    background-color: grey;
+}
+
+#status-group {
+    padding:5px;
+}
+
+#worklist-group {
+    padding:5px;
+}
+
+.vsol-button {
+    height: 40px;
+}
+
+#thumbnails-group ul li {
+    display: inline;
+    list-style: none;
+}
+
+.thumbnail {
+    width: 100px;
+    height: 100px;
+    padding: 3px;
+}
+
+.thumbnail-selected {
+    border-width: 1px;
+    border-color: red;
+    border-style: solid;
+}
+
+#template-thumbnail-li {
+    display: none !important;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewer/Wasm/tsconfig-simple-viewer.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,9 @@
+{
+    "extends" : "../../Web/tsconfig-samples",
+    "compilerOptions": {
+    },
+    "include" : [
+        "simple-viewer.ts",
+        "../../build-wasm/ApplicationCommands_generated.ts"
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SimpleViewerApplicationSingleFile.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,461 @@
+/**
+ * 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 "SampleApplicationBase.h"
+
+#include "../../../Framework/Deprecated/Layers/CircleMeasureTracker.h"
+#include "../../../Framework/Deprecated/Layers/LineMeasureTracker.h"
+#include "../../../Framework/Deprecated/SmartLoader.h"
+#include "../../../Framework/Deprecated/Widgets/LayoutWidget.h"
+#include "../../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
+#include "../../../Framework/Messages/IObserver.h"
+
+#if ORTHANC_ENABLE_WASM==1
+#include "../../../Platforms/Wasm/WasmPlatformApplicationAdapter.h"
+#include "../../../Platforms/Wasm/Defaults.h"
+#endif
+
+#include <Core/Images/Font.h>
+#include <Core/Logging.h>
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SimpleViewerApplication :
+      public SampleSingleCanvasWithButtonsApplicationBase,
+      public ObserverBase<SimpleViewerApplication>
+    {
+    private:
+      class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
+      {
+      private:
+        SimpleViewerApplication&  application_;
+
+      public:
+        ThumbnailInteractor(SimpleViewerApplication&  application) :
+          application_(application)
+        {
+        }
+
+        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                            const Deprecated::ViewportGeometry& view,
+                                                            MouseButton button,
+                                                            KeyboardModifiers modifiers,
+                                                            int viewportX,
+                                                            int viewportY,
+                                                            double x,
+                                                            double y,
+                                                            Deprecated::IStatusBar* statusBar,
+                                                            const std::vector<Deprecated::Touch>& displayTouches)
+        {
+          if (button == MouseButton_Left)
+          {
+            statusBar->SetMessage("selected thumbnail " + widget.GetName());
+            std::string seriesId = widget.GetName().substr(strlen("thumbnail-series-"));
+            application_.SelectSeriesInMainViewport(seriesId);
+          }
+          return NULL;
+        }
+
+        virtual void MouseOver(CairoContext& context,
+                               Deprecated::WorldSceneWidget& widget,
+                               const Deprecated::ViewportGeometry& view,
+                               double x,
+                               double y,
+                               Deprecated::IStatusBar* statusBar)
+        {
+        }
+
+        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
+                                MouseWheelDirection direction,
+                                KeyboardModifiers modifiers,
+                                Deprecated::IStatusBar* statusBar)
+        {
+        }
+
+        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
+                                KeyboardKeys key,
+                                char keyChar,
+                                KeyboardModifiers modifiers,
+                                Deprecated::IStatusBar* statusBar)
+        {
+        }
+      };
+
+      class MainWidgetInteractor : public Deprecated::IWorldSceneInteractor
+      {
+      private:
+        SimpleViewerApplication&  application_;
+        
+      public:
+        MainWidgetInteractor(SimpleViewerApplication&  application) :
+          application_(application)
+        {
+        }
+        
+        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                            const Deprecated::ViewportGeometry& view,
+                                                            MouseButton button,
+                                                            KeyboardModifiers modifiers,
+                                                            int viewportX,
+                                                            int viewportY,
+                                                            double x,
+                                                            double y,
+                                                            Deprecated::IStatusBar* statusBar,
+                                                            const std::vector<Deprecated::Touch>& displayTouches)
+        {
+          if (button == MouseButton_Left)
+          {
+            if (application_.currentTool_ == Tool_LineMeasure)
+            {
+              return new Deprecated::LineMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
+                                            x, y, 255, 0, 0, application_.GetFont());
+            }
+            else if (application_.currentTool_ == Tool_CircleMeasure)
+            {
+              return new Deprecated::CircleMeasureTracker(statusBar, dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice(),
+                                              x, y, 255, 0, 0, application_.GetFont());
+            }
+          }
+          return NULL;
+        }
+
+        virtual void MouseOver(CairoContext& context,
+                               Deprecated::WorldSceneWidget& widget,
+                               const Deprecated::ViewportGeometry& view,
+                               double x,
+                               double y,
+                               Deprecated::IStatusBar* statusBar)
+        {
+          if (statusBar != NULL)
+          {
+            Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+            
+            char buf[64];
+            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
+                    p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+            statusBar->SetMessage(buf);
+          }
+        }
+
+        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
+                                MouseWheelDirection direction,
+                                KeyboardModifiers modifiers,
+                                Deprecated::IStatusBar* statusBar)
+        {
+        }
+
+        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
+                                KeyboardKeys key,
+                                char keyChar,
+                                KeyboardModifiers modifiers,
+                                Deprecated::IStatusBar* statusBar)
+        {
+          switch (keyChar)
+          {
+            case 's':
+              widget.FitContent();
+              break;
+
+            case 'l':
+              application_.currentTool_ = Tool_LineMeasure;
+              break;
+
+            case 'c':
+              application_.currentTool_ = Tool_CircleMeasure;
+              break;
+
+            default:
+              break;
+          }
+        }
+      };
+
+
+#if ORTHANC_ENABLE_WASM==1
+      class SimpleViewerApplicationAdapter : public WasmPlatformApplicationAdapter
+      {
+        SimpleViewerApplication&  viewerApplication_;
+
+      public:
+        SimpleViewerApplicationAdapter(SimpleViewerApplication& application)
+          : WasmPlatformApplicationAdapter(application),
+            viewerApplication_(application)
+        {
+        }
+
+        virtual void HandleSerializedMessageFromWeb(std::string& output, const std::string& input) 
+        {
+          if (input == "select-tool:line-measure")
+          {
+            viewerApplication_.currentTool_ = Tool_LineMeasure;
+            NotifyStatusUpdateFromCppToWebWithString("currentTool=line-measure");
+          }
+          else if (input == "select-tool:circle-measure")
+          {
+            viewerApplication_.currentTool_ = Tool_CircleMeasure;
+            NotifyStatusUpdateFromCppToWebWithString("currentTool=circle-measure");
+          }
+
+          output = "ok";
+        }
+
+        virtual void NotifySerializedMessageFromCppToWeb(const std::string& statusUpdateMessage) 
+        {
+          UpdateStoneApplicationStatusFromCppWithSerializedMessage(statusUpdateMessage.c_str());
+        }
+
+        virtual void NotifyStatusUpdateFromCppToWebWithString(const std::string& statusUpdateMessage) 
+        {
+          UpdateStoneApplicationStatusFromCppWithString(statusUpdateMessage.c_str());
+        }
+
+      };
+#endif
+      enum Tool {
+        Tool_LineMeasure,
+        Tool_CircleMeasure
+      };
+
+      Tool                                 currentTool_;
+      std::unique_ptr<MainWidgetInteractor>  mainWidgetInteractor_;
+      std::unique_ptr<ThumbnailInteractor>   thumbnailInteractor_;
+      Deprecated::LayoutWidget*                        mainLayout_;
+      Deprecated::LayoutWidget*                        thumbnailsLayout_;
+      std::vector<boost::shared_ptr<Deprecated::SliceViewerWidget> >      thumbnails_;
+
+      std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
+      std::map<std::string, Json::Value> seriesTags_;
+
+      unsigned int                         currentInstanceIndex_;
+      Deprecated::WidgetViewport*        wasmViewport1_;
+      Deprecated::WidgetViewport*        wasmViewport2_;
+
+      Deprecated::IStatusBar*                          statusBar_;
+      std::unique_ptr<Deprecated::SmartLoader>           smartLoader_;
+
+      Orthanc::Font                        font_;
+
+    public:
+      SimpleViewerApplication() :
+        currentTool_(Tool_LineMeasure),
+        mainLayout_(NULL),
+        currentInstanceIndex_(0),
+        wasmViewport1_(NULL),
+        wasmViewport2_(NULL)
+      {
+        font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
+//        DeclareIgnoredMessage(MessageType_Widget_ContentChanged);
+      }
+
+      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("studyId", boost::program_options::value<std::string>(),
+           "Orthanc ID of the study")
+          ;
+
+        options.add(generic);
+      }
+
+      virtual void Initialize(StoneApplicationContext* context,
+                              Deprecated::IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        context_ = context;
+        statusBar_ = &statusBar;
+
+        {// initialize viewports and layout
+          mainLayout_ = new Deprecated::LayoutWidget("main-layout");
+          mainLayout_->SetPadding(10);
+          mainLayout_->SetBackgroundCleared(true);
+          mainLayout_->SetBackgroundColor(0, 0, 0);
+          mainLayout_->SetHorizontal();
+
+          boost::shared_ptr<Deprecated::LayoutWidget> thumbnailsLayout_(new Deprecated::LayoutWidget("thumbnail-layout"));
+          thumbnailsLayout_->SetPadding(10);
+          thumbnailsLayout_->SetBackgroundCleared(true);
+          thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
+          thumbnailsLayout_->SetVertical();
+
+          boost::shared_ptr<Deprecated::SliceViewerWidget> widget
+            (new Deprecated::SliceViewerWidget("main-viewport"));
+          SetCentralWidget(widget);
+          //mainWidget_->RegisterObserver(*this);
+
+          // hierarchy
+          mainLayout_->AddWidget(thumbnailsLayout_);
+          mainLayout_->AddWidget(widget);
+
+          // sources
+          smartLoader_.reset(new Deprecated::SmartLoader(context->GetOrthancApiClient()));
+          smartLoader_->SetImageQuality(Deprecated::SliceImageQuality_FullPam);
+
+          mainLayout_->SetTransmitMouseOver(true);
+          mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
+          widget->SetInteractor(*mainWidgetInteractor_);
+          thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
+        }
+
+        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+        statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport");
+
+
+        if (parameters.count("studyId") < 1)
+        {
+          LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
+          context->GetOrthancApiClient()->GetJsonAsync(
+            "/studies",
+            new Deprecated::DeprecatedCallable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
+            (GetSharedObserver(), &SimpleViewerApplication::OnStudyListReceived));
+        }
+        else
+        {
+          SelectStudy(parameters["studyId"].as<std::string>());
+        }
+      }
+
+      void OnStudyListReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
+      {
+        const Json::Value& response = message.GetJson();
+
+        if (response.isArray() &&
+            response.size() >= 1)
+        {
+          SelectStudy(response[0].asString());
+        }
+      }
+      
+      void OnStudyReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
+      {
+        const Json::Value& response = message.GetJson();
+
+        if (response.isObject() && response["Series"].isArray())
+        {
+          for (size_t i=0; i < response["Series"].size(); i++)
+          {
+            context_->GetOrthancApiClient()->GetJsonAsync(
+              "/series/" + response["Series"][(int)i].asString(),
+              new Deprecated::DeprecatedCallable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
+              (GetSharedObserver(), &SimpleViewerApplication::OnSeriesReceived));
+          }
+        }
+      }
+
+      void OnSeriesReceived(const Deprecated::OrthancApiClient::JsonResponseReadyMessage& message)
+      {
+        const Json::Value& response = message.GetJson();
+
+        if (response.isObject() &&
+            response["Instances"].isArray() &&
+            response["Instances"].size() > 0)
+        {
+          // keep track of all instances IDs
+          const std::string& seriesId = response["ID"].asString();
+          seriesTags_[seriesId] = response;
+          instancesIdsPerSeriesId_[seriesId] = std::vector<std::string>();
+          for (size_t i = 0; i < response["Instances"].size(); i++)
+          {
+            const std::string& instanceId = response["Instances"][static_cast<int>(i)].asString();
+            instancesIdsPerSeriesId_[seriesId].push_back(instanceId);
+          }
+
+          // load the first instance in the thumbnail
+          LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
+
+          // if this is the first thumbnail loaded, load the first instance in the mainWidget
+          Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget());
+          if (widget.GetLayerCount() == 0)
+          {
+            smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
+          }
+        }
+      }
+
+      void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
+      {
+        LOG(INFO) << "Loading thumbnail for series " << seriesId;
+        boost::shared_ptr<Deprecated::SliceViewerWidget> thumbnailWidget(new Deprecated::SliceViewerWidget("thumbnail-series-" + seriesId));
+        thumbnails_.push_back(thumbnailWidget);
+        thumbnailsLayout_->AddWidget(thumbnailWidget);
+        Register<Deprecated::SliceViewerWidget::GeometryChangedMessage>(*thumbnailWidget, &SimpleViewerApplication::OnWidgetGeometryChanged);
+        smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
+        thumbnailWidget->SetInteractor(*thumbnailInteractor_);
+      }
+
+      void SelectStudy(const std::string& studyId)
+      {
+        LOG(INFO) << "Selecting study: " << studyId;
+        context_->GetOrthancApiClient()->GetJsonAsync(
+          "/studies/" + studyId, new Deprecated::DeprecatedCallable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
+          (GetSharedObserver(), &SimpleViewerApplication::OnStudyReceived));
+      }
+
+      void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
+      {
+        // TODO: The "const_cast" could probably be replaced by "mainWidget"
+        const_cast<Deprecated::SliceViewerWidget&>(message.GetOrigin()).FitContent();
+      }
+
+      void SelectSeriesInMainViewport(const std::string& seriesId)
+      {
+        Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget());
+        smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
+      }
+
+      const Orthanc::Font& GetFont() const
+      {
+        return font_;
+      }
+      
+      virtual void OnPushButton1Clicked() {}
+      virtual void OnPushButton2Clicked() {}
+      virtual void OnTool1Clicked() { currentTool_ = Tool_LineMeasure;}
+      virtual void OnTool2Clicked() { currentTool_ = Tool_CircleMeasure;}
+
+      virtual void GetButtonNames(std::string& pushButton1,
+                                  std::string& pushButton2,
+                                  std::string& tool1,
+                                  std::string& tool2)
+      {
+        tool1 = "line";
+        tool2 = "circle";
+        pushButton1 = "action1";
+        pushButton2 = "action2";
+      }
+
+#if ORTHANC_ENABLE_WASM==1
+      virtual void InitializeWasm()
+      {
+        AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
+        AttachWidgetToWasmViewport("canvas2", widget);
+      }
+#endif
+
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SingleFrameApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,268 @@
+/**
+ * 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 "SampleApplicationBase.h"
+
+#include "../../../Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h"
+#include "../../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/math/constants/constants.hpp>
+
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SingleFrameApplication :
+      public SampleSingleCanvasApplicationBase,
+      public ObserverBase<SingleFrameApplication>
+    {
+    private:
+      class Interactor : public Deprecated::IWorldSceneInteractor
+      {
+      private:
+        SingleFrameApplication&  application_;
+        
+      public:
+        Interactor(SingleFrameApplication&  application) :
+          application_(application)
+        {
+        }
+        
+        virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& widget,
+                                                                        const Deprecated::ViewportGeometry& view,
+                                                                        MouseButton button,
+                                                                        KeyboardModifiers modifiers,
+                                                                        int viewportX,
+                                                                        int viewportY,
+                                                                        double x,
+                                                                        double y,
+                                                                        Deprecated::IStatusBar* statusBar,
+                                                                        const std::vector<Deprecated::Touch>& displayTouches)
+        {
+          return NULL;
+        }
+
+        virtual void MouseOver(CairoContext& context,
+                               Deprecated::WorldSceneWidget& widget,
+                               const Deprecated::ViewportGeometry& view,
+                               double x,
+                               double y,
+                               Deprecated::IStatusBar* statusBar)
+        {
+          if (statusBar != NULL)
+          {
+            Vector p = dynamic_cast<Deprecated::SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+            
+            char buf[64];
+            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", 
+                    p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+            statusBar->SetMessage(buf);
+          }
+        }
+
+        virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
+                                MouseWheelDirection direction,
+                                KeyboardModifiers modifiers,
+                                Deprecated::IStatusBar* statusBar)
+        {
+          int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
+          
+          switch (direction)
+          {
+            case MouseWheelDirection_Up:
+              application_.OffsetSlice(-scale);
+              break;
+
+            case MouseWheelDirection_Down:
+              application_.OffsetSlice(scale);
+              break;
+
+            default:
+              break;
+          }
+        }
+
+        virtual void KeyPressed(Deprecated::WorldSceneWidget& widget,
+                                KeyboardKeys key,
+                                char keyChar,
+                                KeyboardModifiers modifiers,
+                                Deprecated::IStatusBar* statusBar)
+        {
+          switch (keyChar)
+          {
+            case 's':
+              widget.FitContent();
+              break;
+
+            default:
+              break;
+          }
+        }
+      };
+
+
+      void OffsetSlice(int offset)
+      {
+        if (source_)
+        {
+          int slice = static_cast<int>(slice_) + offset;
+
+          if (slice < 0)
+          {
+            slice = 0;
+          }
+
+          if (slice >= static_cast<int>(source_->GetSlicesCount()))
+          {
+            slice = static_cast<int>(source_->GetSlicesCount()) - 1;
+          }
+
+          if (slice != static_cast<int>(slice_)) 
+          {
+            SetSlice(slice);
+          }   
+        }
+      }
+
+
+      void SetSlice(size_t index)
+      {
+        if (source_ &&
+            index < source_->GetSlicesCount())
+        {
+          slice_ = static_cast<unsigned int>(index);
+          
+#if 1
+          widget_->SetSlice(source_->GetSlice(slice_).GetGeometry());
+#else
+          // TEST for scene extents - Rotate the axes
+          double a = 15.0 / 180.0 * boost::math::constants::pi<double>();
+
+#if 1
+          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
+          Vector y; GeometryToolbox::AssignVector(y, -sin(a), cos(a), 0);
+#else
+          // Flip the normal
+          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
+          Vector y; GeometryToolbox::AssignVector(y, sin(a), -cos(a), 0);
+#endif
+          
+          SliceGeometry s(source_->GetSlice(slice_).GetGeometry().GetOrigin(), x, y);
+          widget_->SetSlice(s);
+#endif
+        }
+      }
+        
+      
+      void OnMainWidgetGeometryReady(const Deprecated::IVolumeSlicer::GeometryReadyMessage& message)
+      {
+        // Once the geometry of the series is downloaded from Orthanc,
+        // display its middle slice, and adapt the viewport to fit this
+        // slice
+        if (source_ &&
+            source_.get() == &message.GetOrigin())
+        {
+          SetSlice(source_->GetSlicesCount() / 2);
+        }
+
+        widget_->FitContent();
+      }
+
+      boost::shared_ptr<Deprecated::SliceViewerWidget>  widget_;
+      std::unique_ptr<Interactor>         mainWidgetInteractor_;
+      boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> source_;
+      unsigned int                      slice_;
+
+    public:
+      SingleFrameApplication() :
+        slice_(0)
+      {
+      }
+      
+      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("instance", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the instance")
+          ("frame", boost::program_options::value<unsigned int>()->default_value(0),
+           "Number of the frame, for multi-frame DICOM instances")
+          ("smooth", boost::program_options::value<bool>()->default_value(true), 
+           "Enable bilinear interpolation to smooth the image")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(StoneApplicationContext* context,
+                              Deprecated::IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        context_ = context;
+
+        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+
+        if (parameters.count("instance") != 1)
+        {
+          LOG(ERROR) << "The instance ID is missing";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::string instance = parameters["instance"].as<std::string>();
+        int frame = parameters["frame"].as<unsigned int>();
+
+        widget_.reset(new Deprecated::SliceViewerWidget("main-widget"));
+        SetCentralWidget(widget_);
+
+        boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer);
+        layer->Connect(context->GetOrthancApiClient());
+        source_ = layer;
+
+        layer->LoadFrame(instance, frame);
+        Register<Deprecated::IVolumeSlicer::GeometryReadyMessage>(*layer, &SingleFrameApplication::OnMainWidgetGeometryReady);
+        widget_->AddLayer(layer);
+
+        Deprecated::RenderStyle s;
+
+        if (parameters["smooth"].as<bool>())
+        {
+          s.interpolation_ = ImageInterpolation_Bilinear;
+        }
+
+        widget_->SetLayerStyle(0, s);
+        widget_->SetTransmitMouseOver(true);
+
+        mainWidgetInteractor_.reset(new Interactor(*this));
+        widget_->SetInteractor(*mainWidgetInteractor_);
+      }
+    };
+
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SingleFrameEditorApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,531 @@
+/**
+ * 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 "SampleApplicationBase.h"
+
+#include "../../../Framework/Radiography/RadiographyLayerCropTracker.h"
+#include "../../../Framework/Radiography/RadiographyLayerMaskTracker.h"
+#include "../../../Framework/Radiography/RadiographyLayerMoveTracker.h"
+#include "../../../Framework/Radiography/RadiographyLayerResizeTracker.h"
+#include "../../../Framework/Radiography/RadiographyLayerRotateTracker.h"
+#include "../../../Framework/Radiography/RadiographyMaskLayer.h"
+#include "../../../Framework/Radiography/RadiographyScene.h"
+#include "../../../Framework/Radiography/RadiographySceneCommand.h"
+#include "../../../Framework/Radiography/RadiographySceneReader.h"
+#include "../../../Framework/Radiography/RadiographySceneWriter.h"
+#include "../../../Framework/Radiography/RadiographyWidget.h"
+#include "../../../Framework/Radiography/RadiographyWindowingTracker.h"
+#include "../../../Framework/Toolbox/TextRenderer.h"
+
+#include <Core/HttpClient.h>
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <Core/Images/PngWriter.h>
+#include <Core/Images/PngReader.h>
+
+
+// Export using PAM is faster than using PNG, but requires Orthanc
+// core >= 1.4.3
+#define EXPORT_USING_PAM  1
+
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class RadiographyEditorInteractor :
+        public Deprecated::IWorldSceneInteractor,
+        public ObserverBase<RadiographyEditorInteractor>
+    {
+    private:
+      enum Tool
+      {
+        Tool_Move,
+        Tool_Rotate,
+        Tool_Crop,
+        Tool_Resize,
+        Tool_Mask,
+        Tool_Windowing
+      };
+
+
+      StoneApplicationContext*  context_;
+      UndoRedoStack             undoRedoStack_;
+      Tool                      tool_;
+      RadiographyMaskLayer*     maskLayer_;
+
+
+      static double GetHandleSize()
+      {
+        return 10.0;
+      }
+
+
+    public:
+      RadiographyEditorInteractor() :
+        context_(NULL),
+        tool_(Tool_Move),
+        maskLayer_(NULL)
+      {
+      }
+
+      void SetContext(StoneApplicationContext& context)
+      {
+        context_ = &context;
+      }
+
+      void SetMaskLayer(RadiographyMaskLayer* maskLayer)
+      {
+        maskLayer_ = maskLayer;
+      }
+      virtual Deprecated::IWorldSceneMouseTracker* CreateMouseTracker(Deprecated::WorldSceneWidget& worldWidget,
+                                                                      const Deprecated::ViewportGeometry& view,
+                                                                      MouseButton button,
+                                                                      KeyboardModifiers modifiers,
+                                                                      int viewportX,
+                                                                      int viewportY,
+                                                                      double x,
+                                                                      double y,
+                                                                      Deprecated::IStatusBar* statusBar,
+                                                                      const std::vector<Deprecated::Touch>& displayTouches)
+      {
+        RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
+
+        if (button == MouseButton_Left)
+        {
+          size_t selected;
+
+          if (tool_ == Tool_Windowing)
+          {
+            return new RadiographyWindowingTracker(
+                  undoRedoStack_,
+                  widget.GetScene(),
+                  widget,
+                  OrthancStone::ImageInterpolation_Nearest,
+                  viewportX, viewportY,
+                  RadiographyWindowingTracker::Action_DecreaseWidth,
+                  RadiographyWindowingTracker::Action_IncreaseWidth,
+                  RadiographyWindowingTracker::Action_DecreaseCenter,
+                  RadiographyWindowingTracker::Action_IncreaseCenter);
+          }
+          else if (!widget.LookupSelectedLayer(selected))
+          {
+            // No layer is currently selected
+            size_t layer;
+            if (widget.GetScene().LookupLayer(layer, x, y))
+            {
+              widget.Select(layer);
+            }
+
+            return NULL;
+          }
+          else if (tool_ == Tool_Crop ||
+                   tool_ == Tool_Resize ||
+                   tool_ == Tool_Mask)
+          {
+            RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
+            
+            ControlPoint controlPoint;
+            if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize()))
+            {
+              switch (tool_)
+              {
+              case Tool_Crop:
+                return new RadiographyLayerCropTracker
+                    (undoRedoStack_, widget.GetScene(), view, selected, controlPoint);
+
+              case Tool_Mask:
+                return new RadiographyLayerMaskTracker
+                    (undoRedoStack_, widget.GetScene(), view, selected, controlPoint);
+
+              case Tool_Resize:
+                return new RadiographyLayerResizeTracker
+                    (undoRedoStack_, widget.GetScene(), selected, controlPoint,
+                     (modifiers & KeyboardModifiers_Shift));
+
+              default:
+                throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+              }
+            }
+            else
+            {
+              size_t layer;
+
+              if (widget.GetScene().LookupLayer(layer, x, y))
+              {
+                widget.Select(layer);
+              }
+              else
+              {
+                widget.Unselect();
+              }
+
+              return NULL;
+            }
+          }
+          else
+          {
+            size_t layer;
+
+            if (widget.GetScene().LookupLayer(layer, x, y))
+            {
+              if (layer == selected)
+              {
+                switch (tool_)
+                {
+                case Tool_Move:
+                  return new RadiographyLayerMoveTracker
+                      (undoRedoStack_, widget.GetScene(), layer, x, y,
+                       (modifiers & KeyboardModifiers_Shift));
+
+                case Tool_Rotate:
+                  return new RadiographyLayerRotateTracker
+                      (undoRedoStack_, widget.GetScene(), view, layer, x, y,
+                       (modifiers & KeyboardModifiers_Shift));
+
+                default:
+                  break;
+                }
+
+                return NULL;
+              }
+              else
+              {
+                widget.Select(layer);
+                return NULL;
+              }
+            }
+            else
+            {
+              widget.Unselect();
+              return NULL;
+            }
+          }
+        }
+        else
+        {
+          return NULL;
+        }
+        return NULL;
+      }
+
+      virtual void MouseOver(CairoContext& context,
+                             Deprecated::WorldSceneWidget& worldWidget,
+                             const Deprecated::ViewportGeometry& view,
+                             double x,
+                             double y,
+                             Deprecated::IStatusBar* statusBar)
+      {
+        RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
+
+#if 0
+        if (statusBar != NULL)
+        {
+          char buf[64];
+          sprintf(buf, "X = %.02f Y = %.02f (in cm)", x / 10.0, y / 10.0);
+          statusBar->SetMessage(buf);
+        }
+#endif
+
+        size_t selected;
+
+        if (widget.LookupSelectedLayer(selected) &&
+            (tool_ == Tool_Crop ||
+             tool_ == Tool_Resize ||
+             tool_ == Tool_Mask))
+        {
+          RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
+
+          ControlPoint controlPoint;
+          if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize()))
+          {
+            double z = 1.0 / view.GetZoom();
+
+            context.SetSourceColor(255, 0, 0);
+            cairo_t* cr = context.GetObject();
+            cairo_set_line_width(cr, 2.0 * z);
+            cairo_move_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y + GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y + GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
+            cairo_stroke(cr);
+          }
+        }
+      }
+
+      virtual void MouseWheel(Deprecated::WorldSceneWidget& widget,
+                              MouseWheelDirection direction,
+                              KeyboardModifiers modifiers,
+                              Deprecated::IStatusBar* statusBar)
+      {
+      }
+
+      virtual void KeyPressed(Deprecated::WorldSceneWidget& worldWidget,
+                              KeyboardKeys key,
+                              char keyChar,
+                              KeyboardModifiers modifiers,
+                              Deprecated::IStatusBar* statusBar)
+      {
+        RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
+
+        switch (keyChar)
+        {
+        case 'a':
+          widget.FitContent();
+          break;
+
+        case 'c':
+          tool_ = Tool_Crop;
+          break;
+
+        case 'm':
+          tool_ = Tool_Mask;
+          widget.Select(1);
+          break;
+
+        case 'd':
+        {
+          // dump to json and reload
+          Json::Value snapshot;
+          RadiographySceneWriter writer;
+          writer.Write(snapshot, widget.GetScene());
+
+          LOG(INFO) << "JSON export was successful: "
+                    << snapshot.toStyledString();
+
+          boost::shared_ptr<RadiographyScene> scene(new RadiographyScene);
+          RadiographySceneReader reader(*scene, *context_->GetOrthancApiClient());
+          reader.Read(snapshot);
+
+          widget.SetScene(scene);
+        };break;
+
+        case 'e':
+        {
+          Orthanc::DicomMap tags;
+
+          // Minimal set of tags to generate a valid CR image
+          tags.SetValue(Orthanc::DICOM_TAG_ACCESSION_NUMBER, "NOPE", false);
+          tags.SetValue(Orthanc::DICOM_TAG_BODY_PART_EXAMINED, "PELVIS", false);
+          tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1", false);
+          //tags.SetValue(Orthanc::DICOM_TAG_LATERALITY, "", false);
+          tags.SetValue(Orthanc::DICOM_TAG_MANUFACTURER, "OSIMIS", false);
+          tags.SetValue(Orthanc::DICOM_TAG_MODALITY, "CR", false);
+          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_BIRTH_DATE, "20000101", false);
+          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ID, "hello", false);
+          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_NAME, "HELLO^WORLD", false);
+          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_ORIENTATION, "", false);
+          tags.SetValue(Orthanc::DICOM_TAG_PATIENT_SEX, "M", false);
+          tags.SetValue(Orthanc::DICOM_TAG_REFERRING_PHYSICIAN_NAME, "HOUSE^MD", false);
+          tags.SetValue(Orthanc::DICOM_TAG_SERIES_NUMBER, "1", false);
+          tags.SetValue(Orthanc::DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false);
+          tags.SetValue(Orthanc::DICOM_TAG_STUDY_ID, "STUDY", false);
+          tags.SetValue(Orthanc::DICOM_TAG_VIEW_POSITION, "", false);
+
+          if (context_ != NULL)
+          {
+            widget.GetScene().ExportDicom(*context_->GetOrthancApiClient(),
+                                          tags, std::string(), 0.1, 0.1, widget.IsInverted(),
+                                          false /* autoCrop */, widget.GetInterpolation(), EXPORT_USING_PAM);
+          }
+
+          break;
+        }
+
+        case 'i':
+          widget.SwitchInvert();
+          break;
+
+        case 't':
+          tool_ = Tool_Move;
+          break;
+
+        case 'n':
+        {
+          switch (widget.GetInterpolation())
+          {
+          case ImageInterpolation_Nearest:
+            LOG(INFO) << "Switching to bilinear interpolation";
+            widget.SetInterpolation(ImageInterpolation_Bilinear);
+            break;
+
+          case ImageInterpolation_Bilinear:
+            LOG(INFO) << "Switching to nearest neighbor interpolation";
+            widget.SetInterpolation(ImageInterpolation_Nearest);
+            break;
+
+          default:
+            throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+          }
+          
+          break;
+        }
+
+        case 'r':
+          tool_ = Tool_Rotate;
+          break;
+
+        case 's':
+          tool_ = Tool_Resize;
+          break;
+
+        case 'w':
+          tool_ = Tool_Windowing;
+          break;
+
+        case 'y':
+          if (modifiers & KeyboardModifiers_Control)
+          {
+            undoRedoStack_.Redo();
+            widget.NotifyContentChanged();
+          }
+          break;
+
+        case 'z':
+          if (modifiers & KeyboardModifiers_Control)
+          {
+            undoRedoStack_.Undo();
+            widget.NotifyContentChanged();
+          }
+          break;
+
+        default:
+          break;
+        }
+      }
+    };
+
+
+
+    class SingleFrameEditorApplication :
+        public SampleSingleCanvasApplicationBase,
+        public IObserver
+    {
+    private:
+      boost::shared_ptr<RadiographyScene>   scene_;
+      RadiographyEditorInteractor           interactor_;
+      RadiographyMaskLayer*                 maskLayer_;
+
+    public:
+      virtual ~SingleFrameEditorApplication()
+      {
+        LOG(WARNING) << "Destroying the application";
+      }
+      
+      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+            ("instance", boost::program_options::value<std::string>(),
+             "Orthanc ID of the instance")
+            ("frame", boost::program_options::value<unsigned int>()->default_value(0),
+             "Number of the frame, for multi-frame DICOM instances")
+            ;
+
+        options.add(generic);
+      }
+
+      virtual void Initialize(StoneApplicationContext* context,
+                              Deprecated::IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        context_ = context;
+        interactor_.SetContext(*context);
+
+        statusBar.SetMessage("Use the key \"a\" to reinitialize the layout");
+        statusBar.SetMessage("Use the key \"c\" to crop");
+        statusBar.SetMessage("Use the key \"e\" to export DICOM to the Orthanc server");
+        statusBar.SetMessage("Use the key \"f\" to switch full screen");
+        statusBar.SetMessage("Use the key \"i\" to invert contrast");
+        statusBar.SetMessage("Use the key \"m\" to modify the mask");
+        statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation");
+        statusBar.SetMessage("Use the key \"r\" to rotate objects");
+        statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM layers)");
+        statusBar.SetMessage("Use the key \"t\" to move (translate) objects");
+        statusBar.SetMessage("Use the key \"w\" to change windowing");
+        
+        statusBar.SetMessage("Use the key \"ctrl-z\" to undo action");
+        statusBar.SetMessage("Use the key \"ctrl-y\" to redo action");
+
+        if (parameters.count("instance") != 1)
+        {
+          LOG(ERROR) << "The instance ID is missing";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::string instance = parameters["instance"].as<std::string>();
+        //int frame = parameters["frame"].as<unsigned int>();
+
+        scene_.reset(new RadiographyScene);
+        
+        RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(*context->GetOrthancApiClient(), instance, 0, false, NULL);
+        //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0);
+        // = scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false, NULL);
+
+#if !defined(ORTHANC_ENABLE_WASM) || ORTHANC_ENABLE_WASM != 1
+        Orthanc::HttpClient::ConfigureSsl(true, "/etc/ssl/certs/ca-certificates.crt");
+#endif
+        
+        //scene_->LoadDicomWebFrame(context->GetWebService());
+        
+        std::vector<Orthanc::ImageProcessing::ImagePoint> mask;
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1100, 100));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1100, 1000));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(2000, 1000));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(2200, 150));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1500, 550));
+        maskLayer_ = dynamic_cast<RadiographyMaskLayer*>(&(scene_->LoadMask(mask, dynamic_cast<RadiographyDicomLayer&>(dicomLayer), 128.0f, NULL)));
+        interactor_.SetMaskLayer(maskLayer_);
+
+        {
+          std::unique_ptr<Orthanc::ImageAccessor> renderedTextAlpha(TextRenderer::Render(Orthanc::EmbeddedResources::UBUNTU_FONT, 100,
+                                                                                    "%öÇaA&#"));
+          RadiographyLayer& layer = scene_->LoadAlphaBitmap(renderedTextAlpha.release(), NULL);
+          dynamic_cast<RadiographyAlphaLayer&>(layer).SetForegroundValue(200.0f * 256.0f);
+        }
+
+        {
+          RadiographyTextLayer::RegisterFont("ubuntu", Orthanc::EmbeddedResources::UBUNTU_FONT);
+          RadiographyLayer& layer = scene_->LoadText("Hello\nworld", "ubuntu", 20, 128, NULL, false);
+          layer.SetResizeable(true);
+        }
+        
+        {
+          RadiographyLayer& layer = scene_->LoadTestBlock(100, 50, NULL);
+          layer.SetResizeable(true);
+          layer.SetPan(0, 200);
+        }
+        
+        boost::shared_ptr<RadiographyWidget> widget(new RadiographyWidget(scene_, "main-widget"));
+        widget->SetTransmitMouseOver(true);
+        widget->SetInteractor(interactor_);
+        SetCentralWidget(widget);
+
+        //scene_->SetWindowing(128, 256);
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SingleVolumeApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,277 @@
+/**
+ * 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 "SampleApplicationBase.h"
+#include "../../../Framework/dev.h"
+#include "../../../Framework/Layers/LineMeasureTracker.h"
+#include "../../../Framework/Layers/CircleMeasureTracker.h"
+
+#include <Core/Toolbox.h>
+#include <Core/Logging.h>
+
+#include <Plugins/Samples/Common/OrthancHttpConnection.h>   // TODO REMOVE
+#include "../../../Framework/Layers/DicomStructureSetSlicer.h"   // TODO REMOVE
+#include "../../../Framework/Toolbox/MessagingToolbox.h"   // TODO REMOVE
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SingleVolumeApplication : public SampleApplicationBase
+    {
+    private:
+      class Interactor : public VolumeImageInteractor
+      {
+      private:
+        SliceViewerWidget&  widget_;
+        size_t        layer_;
+        
+      protected:
+        virtual void NotifySliceContentChange(const ISlicedVolume& volume,
+                                       const size_t& sliceIndex,
+                                       const Slice& slice)
+        {
+          const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume);
+
+          RenderStyle s = widget_.GetLayerStyle(layer_);
+
+          if (image.FitWindowingToRange(s, slice.GetConverter()))
+          {
+            //printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
+            widget_.SetLayerStyle(layer_, s);
+          }
+        }
+
+        virtual void MouseOver(CairoContext& context,
+                               WorldSceneWidget& widget,
+                               const ViewportGeometry& view,
+                               double x,
+                               double y,
+                               IStatusBar* statusBar)
+        {
+          const SliceViewerWidget& w = dynamic_cast<const SliceViewerWidget&>(widget);
+          Vector p = w.GetSlice().MapSliceToWorldCoordinates(x, y);
+          printf("%f %f %f\n", p[0], p[1], p[2]);
+        }
+      
+      public:
+        Interactor(OrthancVolumeImage& volume,
+                   SliceViewerWidget& widget,
+                   VolumeProjection projection,
+                   size_t layer) :
+          VolumeImageInteractor(volume, widget, projection),
+          widget_(widget),
+          layer_(layer)
+        {
+        }
+      };
+
+
+    public:
+      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("series", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the series")
+          ("instance", boost::program_options::value<std::string>(), 
+           "Orthanc ID of a multi-frame instance that describes a 3D volume")
+          ("threads", boost::program_options::value<unsigned int>()->default_value(3), 
+           "Number of download threads")
+          ("projection", boost::program_options::value<std::string>()->default_value("axial"), 
+           "Projection of interest (can be axial, sagittal or coronal)")
+          ("reverse", boost::program_options::value<bool>()->default_value(false), 
+           "Reverse the normal direction of the volume")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        if (parameters.count("series") > 1 ||
+            parameters.count("instance") > 1)
+        {
+          LOG(ERROR) << "Only one series or instance is allowed";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        if (parameters.count("series") == 1 &&
+            parameters.count("instance") == 1)
+        {
+          LOG(ERROR) << "Cannot specify both a series and an instance";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::string series;
+        if (parameters.count("series") == 1)
+        {
+          series = parameters["series"].as<std::string>();
+        }
+        
+        std::string instance;
+        if (parameters.count("instance") == 1)
+        {
+          instance = parameters["instance"].as<std::string>();
+        }
+        
+        if (series.empty() &&
+            instance.empty())
+        {
+          LOG(ERROR) << "The series ID or instance ID is missing";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        //unsigned int threads = parameters["threads"].as<unsigned int>();
+        //bool reverse = parameters["reverse"].as<bool>();
+
+        std::string tmp = parameters["projection"].as<std::string>();
+        Orthanc::Toolbox::ToLowerCase(tmp);
+
+        VolumeProjection projection;
+        if (tmp == "axial")
+        {
+          projection = VolumeProjection_Axial;
+        }
+        else if (tmp == "sagittal")
+        {
+          projection = VolumeProjection_Sagittal;
+        }
+        else if (tmp == "coronal")
+        {
+          projection = VolumeProjection_Coronal;
+        }
+        else
+        {
+          LOG(ERROR) << "Unknown projection: " << tmp;
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::unique_ptr<SliceViewerWidget> widget(new SliceViewerWidget);
+
+#if 1
+        std::unique_ptr<OrthancVolumeImage> volume(new OrthancVolumeImage(context.GetWebService(), true));
+        if (series.empty())
+        {
+          volume->ScheduleLoadInstance(instance);
+        }
+        else
+        {
+          volume->ScheduleLoadSeries(series);
+        }
+
+        widget->AddLayer(new VolumeImageMPRSlicer(*volume));
+
+        context_->AddInteractor(new Interactor(*volume, *widget, projection, 0));
+        context_->AddSlicedVolume(volume.release());
+
+        if (1)
+        {
+          RenderStyle s;
+          //s.drawGrid_ = true;
+          s.alpha_ = 1;
+          s.windowing_ = ImageWindowing_Bone;
+          widget->SetLayerStyle(0, s);
+        }
+        else
+        {
+          RenderStyle s;
+          s.alpha_ = 1;
+          s.applyLut_ = true;
+          s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
+          s.interpolation_ = ImageInterpolation_Bilinear;
+          widget->SetLayerStyle(0, s);
+        }
+#else
+        std::unique_ptr<OrthancVolumeImage> ct(new OrthancVolumeImage(context_->GetWebService(), false));
+        //ct->ScheduleLoadSeries("15a6f44a-ac7b88fe-19c462d9-dddd918e-b01550d8");  // 0178023P
+        //ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d");
+        //ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");  // IBA
+        //ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0");  // 0522c0001 TCIA
+        ct->ScheduleLoadSeries("295e8a13-dfed1320-ba6aebb2-9a13e20f-1b3eb953");  // Captain
+        
+        std::unique_ptr<OrthancVolumeImage> pet(new OrthancVolumeImage(context_->GetWebService(), true));
+        //pet->ScheduleLoadSeries("48d2997f-8e25cd81-dd715b64-bd79cdcc-e8fcee53");  // 0178023P
+        //pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e");
+        //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1
+        //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a"); // IBA 2
+        //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");  // IBA 3
+        //pet->ScheduleLoadInstance("269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c");  // 0522c0001 TCIA
+        pet->ScheduleLoadInstance("f080888c-0ab7528a-f7d9c28c-84980eb1-ff3b0ae6");  // Captain 1
+        //pet->ScheduleLoadInstance("4f78055b-6499a2c5-1e089290-394acc05-3ec781c1");  // Captain 2
+
+        std::unique_ptr<StructureSetLoader> rtStruct(new StructureSetLoader(context_->GetWebService()));
+        //rtStruct->ScheduleLoadInstance("c2ebc17b-6b3548db-5e5da170-b8ecab71-ea03add3");  // 0178023P
+        //rtStruct->ScheduleLoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9");  // IBA
+        //rtStruct->ScheduleLoadInstance("17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20");  // 0522c0001 TCIA
+        rtStruct->ScheduleLoadInstance("96c889ab-29fe5c54-dda6e66c-3949e4da-58f90d75");  // Captain
+        
+        widget->AddLayer(new VolumeImageMPRSlicer(*ct));
+        widget->AddLayer(new VolumeImageMPRSlicer(*pet));
+        widget->AddLayer(new DicomStructureSetSlicer(*rtStruct));
+        
+        context_->AddInteractor(new Interactor(*pet, *widget, projection, 1));
+        //context_->AddInteractor(new VolumeImageInteractor(*ct, *widget, projection));
+
+        context_->AddSlicedVolume(ct.release());
+        context_->AddSlicedVolume(pet.release());
+        context_->AddVolumeLoader(rtStruct.release());
+
+        {
+          RenderStyle s;
+          //s.drawGrid_ = true;
+          s.alpha_ = 1;
+          s.windowing_ = ImageWindowing_Bone;
+          widget->SetLayerStyle(0, s);
+        }
+
+        {
+          RenderStyle s;
+          //s.drawGrid_ = true;
+          s.SetColor(255, 0, 0);  // Draw missing PET layer in red
+          s.alpha_ = 0.5;
+          s.applyLut_ = true;
+          s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
+          s.interpolation_ = ImageInterpolation_Bilinear;
+          s.windowing_ = ImageWindowing_Custom;
+          s.customWindowCenter_ = 0;
+          s.customWindowWidth_ = 128;
+          widget->SetLayerStyle(1, s);
+        }
+#endif
+
+
+        statusBar.SetMessage("Use the keys \"b\", \"l\" and \"d\" to change Hounsfield windowing");
+        statusBar.SetMessage("Use the keys \"t\" to track the (X,Y,Z) mouse coordinates");
+        statusBar.SetMessage("Use the keys \"m\" to measure distances");
+        statusBar.SetMessage("Use the keys \"c\" to draw circles");
+
+        widget->SetTransmitMouseOver(true);
+        context_->SetCentralWidget(widget.release());
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/StoneSampleCommands.yml	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,35 @@
+#
+#        1         2         3         4         5         6         7         8
+# 345678901234567890123456789012345678901234567890123456789012345678901234567890
+#
+rootName: StoneSampleCommands
+
+# +---------------------------------+
+# | Messages from TypeScript to C++ |
+# +---------------------------------+
+
+enum Tool:
+  - LineMeasure
+  - CircleMeasure
+  - Crop
+  - Windowing
+  - Zoom
+  - Pan
+  - Move
+  - Rotate
+  - Resize
+  - Mask
+
+struct SelectTool:
+  __handler: cpp
+  tool: Tool
+
+enum ActionType:
+  - UndoCrop
+  - Rotate
+  - Invert
+
+struct Action:
+  __handler: cpp
+  type: ActionType
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/StoneSampleCommands_generate.py	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,16 @@
+import sys
+import os
+
+# add the generation script location to the search paths
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'Resources', 'CodeGeneration'))
+
+# import the code generation tooling script
+import stonegentool
+
+schemaFile = os.path.join(os.path.dirname(__file__), 'StoneSampleCommands.yml')
+outDir = os.path.dirname(__file__)
+
+# ignition!
+stonegentool.Process(schemaFile, outDir)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/StoneSampleCommands_generated.hpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,703 @@
+/*
+         1         2         3         4         5         6         7
+12345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+Generated on 2019-03-18 12:07:42.696093 by stonegentool
+
+*/
+#pragma once
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <assert.h>
+#include <memory>
+#include <json/json.h>
+
+//#define STONEGEN_NO_CPP11 1
+
+#ifdef STONEGEN_NO_CPP11
+#define StoneSmartPtr std::unique_ptr
+#else 
+#define StoneSmartPtr std::unique_ptr
+#endif 
+
+namespace StoneSampleCommands
+{
+  /** Throws in case of problem */
+  inline void _StoneDeserializeValue(int32_t& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asInt();
+  }
+
+  inline Json::Value _StoneSerializeValue(int32_t value)
+  {
+    Json::Value result(value);
+    return result;
+  }
+
+  inline void _StoneDeserializeValue(Json::Value& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue;
+  }
+
+  inline Json::Value _StoneSerializeValue(Json::Value value)
+  {
+    return value;
+  }
+
+  /** Throws in case of problem */
+  inline void _StoneDeserializeValue(double& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asDouble();
+  }
+
+  inline Json::Value _StoneSerializeValue(double value)
+  {
+    Json::Value result(value);
+    return result;
+  }
+
+  /** Throws in case of problem */
+  inline void _StoneDeserializeValue(bool& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asBool();
+  }
+
+  inline Json::Value _StoneSerializeValue(bool value)
+  {
+    Json::Value result(value);
+    return result;
+  }
+
+  /** Throws in case of problem */
+  inline void _StoneDeserializeValue(
+       std::string& destValue
+     , const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asString();
+  }
+
+  inline Json::Value _StoneSerializeValue(const std::string& value)
+  {
+    // the following is better than 
+    Json::Value result(value.data(),value.data()+value.size());
+    return result;
+  }
+
+  inline std::string MakeIndent(size_t indent)
+  {
+    char* txt = reinterpret_cast<char*>(malloc(indent+1)); // NO EXCEPTION BELOW!!!!!!!!!!!!
+    for(size_t i = 0; i < indent; ++i)
+      txt[i] = ' ';
+    txt[indent] = 0;
+    std::string retVal(txt);
+    free(txt); // NO EXCEPTION ABOVE !!!!!!!!!!
+    return retVal;
+  }
+
+  // generic dumper
+  template<typename T>
+  std::ostream& StoneDumpValue(std::ostream& out, const T& value, size_t indent)
+  {
+    out << MakeIndent(indent) << value;
+    return out;
+  }
+
+  // string dumper
+  inline std::ostream& StoneDumpValue(std::ostream& out, const std::string& value, size_t indent)
+  {
+    out << MakeIndent(indent) << "\"" << value  << "\"";
+    return out;
+  }
+
+  /** Throws in case of problem */
+  template<typename T>
+  void _StoneDeserializeValue(
+    std::map<std::string, T>& destValue, const Json::Value& jsonValue)
+  {
+    destValue.clear();
+    for (
+      Json::Value::const_iterator itr = jsonValue.begin();
+      itr != jsonValue.end();
+      itr++)
+    {
+      std::string key;
+      _StoneDeserializeValue(key, itr.key());
+
+      T innerDestValue;
+      _StoneDeserializeValue(innerDestValue, *itr);
+
+      destValue[key] = innerDestValue;
+    }
+  }
+
+  template<typename T>
+  Json::Value _StoneSerializeValue(const std::map<std::string,T>& value)
+  {
+    Json::Value result(Json::objectValue);
+
+    for (typename std::map<std::string, T>::const_iterator it = value.cbegin();
+      it != value.cend(); ++it)
+    {
+      // it->first it->second
+      result[it->first] = _StoneSerializeValue(it->second);
+    }
+    return result;
+  }
+
+  template<typename T>
+  std::ostream& StoneDumpValue(std::ostream& out, const std::map<std::string,T>& value, size_t indent)
+  {
+    out << MakeIndent(indent) << "{\n";
+    for (typename std::map<std::string, T>::const_iterator it = value.cbegin();
+      it != value.cend(); ++it)
+    {
+      out << MakeIndent(indent+2) << "\"" << it->first << "\" : ";
+      StoneDumpValue(out, it->second, indent+2);
+    }
+    out << MakeIndent(indent) << "}\n";
+    return out;
+  }
+
+  /** Throws in case of problem */
+  template<typename T>
+  void _StoneDeserializeValue(
+    std::vector<T>& destValue, const Json::Value& jsonValue)
+  {
+    destValue.clear();
+    destValue.reserve(jsonValue.size());
+    for (Json::Value::ArrayIndex i = 0; i != jsonValue.size(); i++)
+    {
+      T innerDestValue;
+      _StoneDeserializeValue(innerDestValue, jsonValue[i]);
+      destValue.push_back(innerDestValue);
+    }
+  }
+
+  template<typename T>
+  Json::Value _StoneSerializeValue(const std::vector<T>& value)
+  {
+    Json::Value result(Json::arrayValue);
+    for (size_t i = 0; i < value.size(); ++i)
+    {
+      result.append(_StoneSerializeValue(value[i]));
+    }
+    return result;
+  }
+
+  template<typename T>
+  std::ostream& StoneDumpValue(std::ostream& out, const std::vector<T>& value, size_t indent)
+  {
+    out << MakeIndent(indent) << "[\n";
+    for (size_t i = 0; i < value.size(); ++i)
+    {
+      StoneDumpValue(out, value[i], indent+2);
+    }
+    out << MakeIndent(indent) << "]\n";
+    return out;
+  }
+
+  inline void StoneCheckSerializedValueTypeGeneric(const Json::Value& value)
+  {
+    if ((!value.isMember("type")) || (!value["type"].isString()))
+    {
+      std::stringstream ss;
+      ss << "Cannot deserialize value ('type' key invalid)";
+      throw std::runtime_error(ss.str());
+    }
+  }
+
+  inline void StoneCheckSerializedValueType(
+    const Json::Value& value, std::string typeStr)
+  {
+    StoneCheckSerializedValueTypeGeneric(value);
+
+    std::string actTypeStr = value["type"].asString();
+    if (actTypeStr != typeStr)
+    {
+      std::stringstream ss;
+      ss << "Cannot deserialize type" << actTypeStr
+        << "into " << typeStr;
+      throw std::runtime_error(ss.str());
+    }
+  }
+
+  // end of generic methods
+
+// end of generic methods
+
+  enum Tool {
+    Tool_LineMeasure,
+    Tool_CircleMeasure,
+    Tool_Crop,
+    Tool_Windowing,
+    Tool_Zoom,
+    Tool_Pan,
+    Tool_Move,
+    Tool_Rotate,
+    Tool_Resize,
+    Tool_Mask,
+  };
+
+  inline std::string ToString(const Tool& value)
+  {
+    if( value == Tool_LineMeasure)
+    {
+      return std::string("LineMeasure");
+    }
+    if( value == Tool_CircleMeasure)
+    {
+      return std::string("CircleMeasure");
+    }
+    if( value == Tool_Crop)
+    {
+      return std::string("Crop");
+    }
+    if( value == Tool_Windowing)
+    {
+      return std::string("Windowing");
+    }
+    if( value == Tool_Zoom)
+    {
+      return std::string("Zoom");
+    }
+    if( value == Tool_Pan)
+    {
+      return std::string("Pan");
+    }
+    if( value == Tool_Move)
+    {
+      return std::string("Move");
+    }
+    if( value == Tool_Rotate)
+    {
+      return std::string("Rotate");
+    }
+    if( value == Tool_Resize)
+    {
+      return std::string("Resize");
+    }
+    if( value == Tool_Mask)
+    {
+      return std::string("Mask");
+    }
+    std::stringstream ss;
+    ss << "Value \"" << value << "\" cannot be converted to Tool. Possible values are: "
+        << " LineMeasure = " << static_cast<int64_t>(Tool_LineMeasure)  << ", " 
+        << " CircleMeasure = " << static_cast<int64_t>(Tool_CircleMeasure)  << ", " 
+        << " Crop = " << static_cast<int64_t>(Tool_Crop)  << ", " 
+        << " Windowing = " << static_cast<int64_t>(Tool_Windowing)  << ", " 
+        << " Zoom = " << static_cast<int64_t>(Tool_Zoom)  << ", " 
+        << " Pan = " << static_cast<int64_t>(Tool_Pan)  << ", " 
+        << " Move = " << static_cast<int64_t>(Tool_Move)  << ", " 
+        << " Rotate = " << static_cast<int64_t>(Tool_Rotate)  << ", " 
+        << " Resize = " << static_cast<int64_t>(Tool_Resize)  << ", " 
+        << " Mask = " << static_cast<int64_t>(Tool_Mask)  << ", " 
+        << std::endl;
+    std::string msg = ss.str();
+    throw std::runtime_error(msg);
+  }
+
+  inline void FromString(Tool& value, std::string strValue)
+  {
+    if( strValue == std::string("LineMeasure") )
+    {
+      value = Tool_LineMeasure;
+      return;
+    }
+    if( strValue == std::string("CircleMeasure") )
+    {
+      value = Tool_CircleMeasure;
+      return;
+    }
+    if( strValue == std::string("Crop") )
+    {
+      value = Tool_Crop;
+      return;
+    }
+    if( strValue == std::string("Windowing") )
+    {
+      value = Tool_Windowing;
+      return;
+    }
+    if( strValue == std::string("Zoom") )
+    {
+      value = Tool_Zoom;
+      return;
+    }
+    if( strValue == std::string("Pan") )
+    {
+      value = Tool_Pan;
+      return;
+    }
+    if( strValue == std::string("Move") )
+    {
+      value = Tool_Move;
+      return;
+    }
+    if( strValue == std::string("Rotate") )
+    {
+      value = Tool_Rotate;
+      return;
+    }
+    if( strValue == std::string("Resize") )
+    {
+      value = Tool_Resize;
+      return;
+    }
+    if( strValue == std::string("Mask") )
+    {
+      value = Tool_Mask;
+      return;
+    }
+
+    std::stringstream ss;
+    ss << "String \"" << strValue << "\" cannot be converted to Tool. Possible values are: LineMeasure CircleMeasure Crop Windowing Zoom Pan Move Rotate Resize Mask ";
+    std::string msg = ss.str();
+    throw std::runtime_error(msg);
+  }
+
+
+  inline void _StoneDeserializeValue(
+    Tool& destValue, const Json::Value& jsonValue)
+  {
+    FromString(destValue, jsonValue.asString());
+  }
+
+  inline Json::Value _StoneSerializeValue(const Tool& value)
+  {
+    std::string strValue = ToString(value);
+    return Json::Value(strValue);
+  }
+
+  inline std::ostream& StoneDumpValue(std::ostream& out, const Tool& value, size_t indent = 0)
+  {
+    if( value == Tool_LineMeasure)
+    {
+      out << MakeIndent(indent) << "LineMeasure" << std::endl;
+    }
+    if( value == Tool_CircleMeasure)
+    {
+      out << MakeIndent(indent) << "CircleMeasure" << std::endl;
+    }
+    if( value == Tool_Crop)
+    {
+      out << MakeIndent(indent) << "Crop" << std::endl;
+    }
+    if( value == Tool_Windowing)
+    {
+      out << MakeIndent(indent) << "Windowing" << std::endl;
+    }
+    if( value == Tool_Zoom)
+    {
+      out << MakeIndent(indent) << "Zoom" << std::endl;
+    }
+    if( value == Tool_Pan)
+    {
+      out << MakeIndent(indent) << "Pan" << std::endl;
+    }
+    if( value == Tool_Move)
+    {
+      out << MakeIndent(indent) << "Move" << std::endl;
+    }
+    if( value == Tool_Rotate)
+    {
+      out << MakeIndent(indent) << "Rotate" << std::endl;
+    }
+    if( value == Tool_Resize)
+    {
+      out << MakeIndent(indent) << "Resize" << std::endl;
+    }
+    if( value == Tool_Mask)
+    {
+      out << MakeIndent(indent) << "Mask" << std::endl;
+    }
+    return out;
+  }
+
+
+  enum ActionType {
+    ActionType_UndoCrop,
+    ActionType_Rotate,
+    ActionType_Invert,
+  };
+
+  inline std::string ToString(const ActionType& value)
+  {
+    if( value == ActionType_UndoCrop)
+    {
+      return std::string("UndoCrop");
+    }
+    if( value == ActionType_Rotate)
+    {
+      return std::string("Rotate");
+    }
+    if( value == ActionType_Invert)
+    {
+      return std::string("Invert");
+    }
+    std::stringstream ss;
+    ss << "Value \"" << value << "\" cannot be converted to ActionType. Possible values are: "
+        << " UndoCrop = " << static_cast<int64_t>(ActionType_UndoCrop)  << ", " 
+        << " Rotate = " << static_cast<int64_t>(ActionType_Rotate)  << ", " 
+        << " Invert = " << static_cast<int64_t>(ActionType_Invert)  << ", " 
+        << std::endl;
+    std::string msg = ss.str();
+    throw std::runtime_error(msg);
+  }
+
+  inline void FromString(ActionType& value, std::string strValue)
+  {
+    if( strValue == std::string("UndoCrop") )
+    {
+      value = ActionType_UndoCrop;
+      return;
+    }
+    if( strValue == std::string("Rotate") )
+    {
+      value = ActionType_Rotate;
+      return;
+    }
+    if( strValue == std::string("Invert") )
+    {
+      value = ActionType_Invert;
+      return;
+    }
+
+    std::stringstream ss;
+    ss << "String \"" << strValue << "\" cannot be converted to ActionType. Possible values are: UndoCrop Rotate Invert ";
+    std::string msg = ss.str();
+    throw std::runtime_error(msg);
+  }
+
+
+  inline void _StoneDeserializeValue(
+    ActionType& destValue, const Json::Value& jsonValue)
+  {
+    FromString(destValue, jsonValue.asString());
+  }
+
+  inline Json::Value _StoneSerializeValue(const ActionType& value)
+  {
+    std::string strValue = ToString(value);
+    return Json::Value(strValue);
+  }
+
+  inline std::ostream& StoneDumpValue(std::ostream& out, const ActionType& value, size_t indent = 0)
+  {
+    if( value == ActionType_UndoCrop)
+    {
+      out << MakeIndent(indent) << "UndoCrop" << std::endl;
+    }
+    if( value == ActionType_Rotate)
+    {
+      out << MakeIndent(indent) << "Rotate" << std::endl;
+    }
+    if( value == ActionType_Invert)
+    {
+      out << MakeIndent(indent) << "Invert" << std::endl;
+    }
+    return out;
+  }
+
+
+
+#ifdef _MSC_VER
+#pragma region SelectTool
+#endif //_MSC_VER
+
+  struct SelectTool
+  {
+    Tool tool;
+
+    SelectTool(Tool tool = Tool())
+    {
+      this->tool = tool;
+    }
+  };
+
+  inline void _StoneDeserializeValue(SelectTool& destValue, const Json::Value& value)
+  {
+    _StoneDeserializeValue(destValue.tool, value["tool"]);
+    }
+
+  inline Json::Value _StoneSerializeValue(const SelectTool& value)
+  {
+    Json::Value result(Json::objectValue);
+    result["tool"] = _StoneSerializeValue(value.tool);
+
+    return result;
+  }
+
+  inline std::ostream& StoneDumpValue(std::ostream& out, const SelectTool& value, size_t indent = 0)
+  {
+    out << MakeIndent(indent) << "{\n";
+    out << MakeIndent(indent) << "tool:\n";
+    StoneDumpValue(out, value.tool,indent+2);
+    out << "\n";
+
+    out << MakeIndent(indent) << "}\n";
+    return out;
+  }
+
+  inline void StoneDeserialize(SelectTool& destValue, const Json::Value& value)
+  {
+    StoneCheckSerializedValueType(value, "StoneSampleCommands.SelectTool");
+    _StoneDeserializeValue(destValue, value["value"]);
+  }
+
+  inline Json::Value StoneSerializeToJson(const SelectTool& value)
+  {
+    Json::Value result(Json::objectValue);
+    result["type"] = "StoneSampleCommands.SelectTool";
+    result["value"] = _StoneSerializeValue(value);
+    return result;
+  }
+
+  inline std::string StoneSerialize(const SelectTool& value)
+  {
+    Json::Value resultJson = StoneSerializeToJson(value);
+    std::string resultStr = resultJson.toStyledString();
+    return resultStr;
+  }
+
+#ifdef _MSC_VER
+#pragma endregion SelectTool
+#endif //_MSC_VER
+
+#ifdef _MSC_VER
+#pragma region Action
+#endif //_MSC_VER
+
+  struct Action
+  {
+    ActionType type;
+
+    Action(ActionType type = ActionType())
+    {
+      this->type = type;
+    }
+  };
+
+  inline void _StoneDeserializeValue(Action& destValue, const Json::Value& value)
+  {
+    _StoneDeserializeValue(destValue.type, value["type"]);
+    }
+
+  inline Json::Value _StoneSerializeValue(const Action& value)
+  {
+    Json::Value result(Json::objectValue);
+    result["type"] = _StoneSerializeValue(value.type);
+
+    return result;
+  }
+
+  inline std::ostream& StoneDumpValue(std::ostream& out, const Action& value, size_t indent = 0)
+  {
+    out << MakeIndent(indent) << "{\n";
+    out << MakeIndent(indent) << "type:\n";
+    StoneDumpValue(out, value.type,indent+2);
+    out << "\n";
+
+    out << MakeIndent(indent) << "}\n";
+    return out;
+  }
+
+  inline void StoneDeserialize(Action& destValue, const Json::Value& value)
+  {
+    StoneCheckSerializedValueType(value, "StoneSampleCommands.Action");
+    _StoneDeserializeValue(destValue, value["value"]);
+  }
+
+  inline Json::Value StoneSerializeToJson(const Action& value)
+  {
+    Json::Value result(Json::objectValue);
+    result["type"] = "StoneSampleCommands.Action";
+    result["value"] = _StoneSerializeValue(value);
+    return result;
+  }
+
+  inline std::string StoneSerialize(const Action& value)
+  {
+    Json::Value resultJson = StoneSerializeToJson(value);
+    std::string resultStr = resultJson.toStyledString();
+    return resultStr;
+  }
+
+#ifdef _MSC_VER
+#pragma endregion Action
+#endif //_MSC_VER
+
+#ifdef _MSC_VER
+#pragma region Dispatching code
+#endif //_MSC_VER
+
+  class IHandler
+  {
+  public:
+    virtual bool Handle(const SelectTool& value) = 0;
+    virtual bool Handle(const Action& value) = 0;
+  };
+
+  /** Service function for StoneDispatchToHandler */
+  inline bool StoneDispatchJsonToHandler(
+    const Json::Value& jsonValue, IHandler* handler)
+  {
+    StoneCheckSerializedValueTypeGeneric(jsonValue);
+    std::string type = jsonValue["type"].asString();
+    if (type == "")
+    {
+      // this should never ever happen
+      throw std::runtime_error("Caught empty type while dispatching");
+    }
+    else if (type == "StoneSampleCommands.SelectTool")
+    {
+      SelectTool value;
+      _StoneDeserializeValue(value, jsonValue["value"]);
+      return handler->Handle(value);
+    }
+    else if (type == "StoneSampleCommands.Action")
+    {
+      Action value;
+      _StoneDeserializeValue(value, jsonValue["value"]);
+      return handler->Handle(value);
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  /** Takes a serialized type and passes this to the handler */
+  inline bool StoneDispatchToHandler(std::string strValue, IHandler* handler)
+  {
+    Json::Value readValue;
+
+    Json::CharReaderBuilder builder;
+    Json::CharReader* reader = builder.newCharReader();
+
+    StoneSmartPtr<Json::CharReader> ptr(reader);
+
+    std::string errors;
+
+    bool ok = reader->parse(
+      strValue.c_str(),
+      strValue.c_str() + strValue.size(),
+      &readValue,
+      &errors
+    );
+    if (!ok)
+    {
+      std::stringstream ss;
+      ss << "Jsoncpp parsing error: " << errors;
+      throw std::runtime_error(ss.str());
+    }
+    return StoneDispatchJsonToHandler(readValue, handler);
+  }
+
+#ifdef _MSC_VER
+#pragma endregion Dispatching code
+#endif //_MSC_VER
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/StoneSampleCommands_generated.ts	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,333 @@
+/*
+         1         2         3         4         5         6         7
+12345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+Generated on 2019-03-18 12:07:42.696093 by stonegentool
+
+*/
+
+function StoneCheckSerializedValueType(value: any, typeStr: string)
+{
+  StoneCheckSerializedValueTypeGeneric(value);
+
+  if (value['type'] != typeStr)
+  {
+    throw new Error(
+      `Cannot deserialize type ${value['type']} into ${typeStr}`);
+  }
+}
+
+function isString(val: any) :boolean
+{
+  return ((typeof val === 'string') || (val instanceof String));
+}
+
+function StoneCheckSerializedValueTypeGeneric(value: any)
+{
+  // console.//log("+-------------------------------------------------+");
+  // console.//log("|            StoneCheckSerializedValueTypeGeneric |");
+  // console.//log("+-------------------------------------------------+");
+  // console.//log("value = ");
+  // console.//log(value);
+  if ( (!('type' in value)) || (!isString(value.type)) )
+  {
+    throw new Error(
+      "Cannot deserialize value ('type' key invalid)");
+  }
+}
+
+// end of generic methods
+
+export enum Tool {
+  LineMeasure = "LineMeasure",
+  CircleMeasure = "CircleMeasure",
+  Crop = "Crop",
+  Windowing = "Windowing",
+  Zoom = "Zoom",
+  Pan = "Pan",
+  Move = "Move",
+  Rotate = "Rotate",
+  Resize = "Resize",
+  Mask = "Mask"
+};
+
+export function Tool_FromString(strValue:string) : Tool
+{
+  if( strValue == "LineMeasure" )
+  {
+    return Tool.LineMeasure;
+  }
+  if( strValue == "CircleMeasure" )
+  {
+    return Tool.CircleMeasure;
+  }
+  if( strValue == "Crop" )
+  {
+    return Tool.Crop;
+  }
+  if( strValue == "Windowing" )
+  {
+    return Tool.Windowing;
+  }
+  if( strValue == "Zoom" )
+  {
+    return Tool.Zoom;
+  }
+  if( strValue == "Pan" )
+  {
+    return Tool.Pan;
+  }
+  if( strValue == "Move" )
+  {
+    return Tool.Move;
+  }
+  if( strValue == "Rotate" )
+  {
+    return Tool.Rotate;
+  }
+  if( strValue == "Resize" )
+  {
+    return Tool.Resize;
+  }
+  if( strValue == "Mask" )
+  {
+    return Tool.Mask;
+  }
+
+  let msg : string =  `String ${strValue} cannot be converted to Tool. Possible values are: LineMeasure, CircleMeasure, Crop, Windowing, Zoom, Pan, Move, Rotate, Resize, Mask`;
+  throw new Error(msg);
+}
+
+export function Tool_ToString(value:Tool) : string
+{
+  if( value == Tool.LineMeasure )
+  {
+    return "LineMeasure";
+  }
+  if( value == Tool.CircleMeasure )
+  {
+    return "CircleMeasure";
+  }
+  if( value == Tool.Crop )
+  {
+    return "Crop";
+  }
+  if( value == Tool.Windowing )
+  {
+    return "Windowing";
+  }
+  if( value == Tool.Zoom )
+  {
+    return "Zoom";
+  }
+  if( value == Tool.Pan )
+  {
+    return "Pan";
+  }
+  if( value == Tool.Move )
+  {
+    return "Move";
+  }
+  if( value == Tool.Rotate )
+  {
+    return "Rotate";
+  }
+  if( value == Tool.Resize )
+  {
+    return "Resize";
+  }
+  if( value == Tool.Mask )
+  {
+    return "Mask";
+  }
+
+  let msg : string = `Value ${value} cannot be converted to Tool. Possible values are: `;
+  {
+    let _LineMeasure_enumValue : string = Tool.LineMeasure; // enums are strings in stonecodegen, so this will work.
+    let msg_LineMeasure : string = `LineMeasure (${_LineMeasure_enumValue}), `;
+    msg = msg + msg_LineMeasure;
+  }
+  {
+    let _CircleMeasure_enumValue : string = Tool.CircleMeasure; // enums are strings in stonecodegen, so this will work.
+    let msg_CircleMeasure : string = `CircleMeasure (${_CircleMeasure_enumValue}), `;
+    msg = msg + msg_CircleMeasure;
+  }
+  {
+    let _Crop_enumValue : string = Tool.Crop; // enums are strings in stonecodegen, so this will work.
+    let msg_Crop : string = `Crop (${_Crop_enumValue}), `;
+    msg = msg + msg_Crop;
+  }
+  {
+    let _Windowing_enumValue : string = Tool.Windowing; // enums are strings in stonecodegen, so this will work.
+    let msg_Windowing : string = `Windowing (${_Windowing_enumValue}), `;
+    msg = msg + msg_Windowing;
+  }
+  {
+    let _Zoom_enumValue : string = Tool.Zoom; // enums are strings in stonecodegen, so this will work.
+    let msg_Zoom : string = `Zoom (${_Zoom_enumValue}), `;
+    msg = msg + msg_Zoom;
+  }
+  {
+    let _Pan_enumValue : string = Tool.Pan; // enums are strings in stonecodegen, so this will work.
+    let msg_Pan : string = `Pan (${_Pan_enumValue}), `;
+    msg = msg + msg_Pan;
+  }
+  {
+    let _Move_enumValue : string = Tool.Move; // enums are strings in stonecodegen, so this will work.
+    let msg_Move : string = `Move (${_Move_enumValue}), `;
+    msg = msg + msg_Move;
+  }
+  {
+    let _Rotate_enumValue : string = Tool.Rotate; // enums are strings in stonecodegen, so this will work.
+    let msg_Rotate : string = `Rotate (${_Rotate_enumValue}), `;
+    msg = msg + msg_Rotate;
+  }
+  {
+    let _Resize_enumValue : string = Tool.Resize; // enums are strings in stonecodegen, so this will work.
+    let msg_Resize : string = `Resize (${_Resize_enumValue}), `;
+    msg = msg + msg_Resize;
+  }
+  {
+    let _Mask_enumValue : string = Tool.Mask; // enums are strings in stonecodegen, so this will work.
+    let msg_Mask : string = `Mask (${_Mask_enumValue})`;
+    msg = msg + msg_Mask;
+  }
+  throw new Error(msg);
+}
+
+export enum ActionType {
+  UndoCrop = "UndoCrop",
+  Rotate = "Rotate",
+  Invert = "Invert"
+};
+
+export function ActionType_FromString(strValue:string) : ActionType
+{
+  if( strValue == "UndoCrop" )
+  {
+    return ActionType.UndoCrop;
+  }
+  if( strValue == "Rotate" )
+  {
+    return ActionType.Rotate;
+  }
+  if( strValue == "Invert" )
+  {
+    return ActionType.Invert;
+  }
+
+  let msg : string =  `String ${strValue} cannot be converted to ActionType. Possible values are: UndoCrop, Rotate, Invert`;
+  throw new Error(msg);
+}
+
+export function ActionType_ToString(value:ActionType) : string
+{
+  if( value == ActionType.UndoCrop )
+  {
+    return "UndoCrop";
+  }
+  if( value == ActionType.Rotate )
+  {
+    return "Rotate";
+  }
+  if( value == ActionType.Invert )
+  {
+    return "Invert";
+  }
+
+  let msg : string = `Value ${value} cannot be converted to ActionType. Possible values are: `;
+  {
+    let _UndoCrop_enumValue : string = ActionType.UndoCrop; // enums are strings in stonecodegen, so this will work.
+    let msg_UndoCrop : string = `UndoCrop (${_UndoCrop_enumValue}), `;
+    msg = msg + msg_UndoCrop;
+  }
+  {
+    let _Rotate_enumValue : string = ActionType.Rotate; // enums are strings in stonecodegen, so this will work.
+    let msg_Rotate : string = `Rotate (${_Rotate_enumValue}), `;
+    msg = msg + msg_Rotate;
+  }
+  {
+    let _Invert_enumValue : string = ActionType.Invert; // enums are strings in stonecodegen, so this will work.
+    let msg_Invert : string = `Invert (${_Invert_enumValue})`;
+    msg = msg + msg_Invert;
+  }
+  throw new Error(msg);
+}
+
+
+
+export class SelectTool {
+  tool:Tool;
+
+  constructor() {
+  }
+
+  public StoneSerialize(): string {
+    let container: object = {};
+    container['type'] = 'StoneSampleCommands.SelectTool';
+    container['value'] = this;
+    return JSON.stringify(container);
+  }
+
+  public static StoneDeserialize(valueStr: string) : SelectTool
+  {
+    let value: any = JSON.parse(valueStr);
+    StoneCheckSerializedValueType(value, 'StoneSampleCommands.SelectTool');
+    let result: SelectTool = value['value'] as SelectTool;
+    return result;
+  }
+}
+export class Action {
+  type:ActionType;
+
+  constructor() {
+  }
+
+  public StoneSerialize(): string {
+    let container: object = {};
+    container['type'] = 'StoneSampleCommands.Action';
+    container['value'] = this;
+    return JSON.stringify(container);
+  }
+
+  public static StoneDeserialize(valueStr: string) : Action
+  {
+    let value: any = JSON.parse(valueStr);
+    StoneCheckSerializedValueType(value, 'StoneSampleCommands.Action');
+    let result: Action = value['value'] as Action;
+    return result;
+  }
+}
+
+export interface IHandler {
+};
+
+/** Service function for StoneDispatchToHandler */
+export function StoneDispatchJsonToHandler(
+  jsonValue: any, handler: IHandler): boolean
+{
+  StoneCheckSerializedValueTypeGeneric(jsonValue);
+  let type: string = jsonValue["type"];
+  if (type == "")
+  {
+    // this should never ever happen
+    throw new Error("Caught empty type while dispatching");
+  }
+  else
+  {
+    return false;
+  }
+}
+
+/** Takes a serialized type and passes this to the handler */
+export function StoneDispatchToHandler(
+  strValue: string, handler: IHandler): boolean
+{
+  // console.//log("+------------------------------------------------+");
+  // console.//log("|            StoneDispatchToHandler              |");
+  // console.//log("+------------------------------------------------+");
+  // console.//log("strValue = ");
+  // console.//log(strValue);
+  let jsonValue: any = JSON.parse(strValue)
+  return StoneDispatchJsonToHandler(jsonValue, handler);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/SynchronizedSeriesApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,109 @@
+/**
+ * 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 "SampleInteractor.h"
+
+#include "../../../Framework/Toolbox/OrthancSeriesLoader.h"
+#include "../../../Framework/Layers/SeriesFrameRendererFactory.h"
+#include "../../../Framework/Layers/ReferenceLineFactory.h"
+#include "../../../Framework/Widgets/LayoutWidget.h"
+
+#include <Core/Logging.h>
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class SynchronizedSeriesApplication : public SampleApplicationBase
+    {
+    private:   
+      LayeredSceneWidget* CreateSeriesWidget(BasicApplicationContext& context,
+                                             const std::string& series)
+      {
+        std::unique_ptr<ISeriesLoader> loader
+          (new OrthancSeriesLoader(context.GetWebService().GetConnection(), series));
+
+        std::unique_ptr<SampleInteractor> interactor(new SampleInteractor(*loader, false));
+
+        std::unique_ptr<LayeredSceneWidget> widget(new LayeredSceneWidget);
+        widget->AddLayer(new SeriesFrameRendererFactory(loader.release(), false));
+        widget->SetSlice(interactor->GetCursor().GetCurrentSlice());
+        widget->SetInteractor(*interactor);
+
+        context.AddInteractor(interactor.release());
+
+        return widget.release();
+      }
+
+    public:
+      virtual void DeclareCommandLineOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("a", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the 1st series")
+          ("b", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the 2nd series")
+          ("c", boost::program_options::value<std::string>(), 
+           "Orthanc ID of the 3rd series")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(BasicApplicationContext& context,
+                              IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        if (parameters.count("a") != 1 ||
+            parameters.count("b") != 1 ||
+            parameters.count("c") != 1)
+        {
+          LOG(ERROR) << "At least one of the three series IDs is missing";
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+        }
+
+        std::unique_ptr<LayeredSceneWidget> a(CreateSeriesWidget(context, parameters["a"].as<std::string>()));
+        std::unique_ptr<LayeredSceneWidget> b(CreateSeriesWidget(context, parameters["b"].as<std::string>()));
+        std::unique_ptr<LayeredSceneWidget> c(CreateSeriesWidget(context, parameters["c"].as<std::string>()));
+
+        ReferenceLineFactory::Configure(*a, *b);
+        ReferenceLineFactory::Configure(*a, *c);
+        ReferenceLineFactory::Configure(*b, *c);
+
+        std::unique_ptr<LayoutWidget> layout(new LayoutWidget);
+        layout->SetPadding(5);
+        layout->AddWidget(a.release());
+
+        std::unique_ptr<LayoutWidget> layoutB(new LayoutWidget);
+        layoutB->SetVertical();
+        layoutB->SetPadding(5);
+        layoutB->AddWidget(b.release());
+        layoutB->AddWidget(c.release());
+        layout->AddWidget(layoutB.release());
+
+        context.SetCentralWidget(layout.release());        
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/TestPatternApplication.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,63 @@
+/**
+ * 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 "SampleApplicationBase.h"
+
+#include "../../../Framework/Widgets/TestCairoWidget.h"
+#include "../../../Framework/Widgets/TestWorldSceneWidget.h"
+#include "../../../Framework/Widgets/LayoutWidget.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class TestPatternApplication : public SampleApplicationBase
+    {
+    public:
+      virtual void DeclareStartupOptions(boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic("Sample options");
+        generic.add_options()
+          ("animate", boost::program_options::value<bool>()->default_value(true), "Animate the test pattern")
+          ;
+
+        options.add(generic);    
+      }
+
+      virtual void Initialize(IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters)
+      {
+        using namespace OrthancStone;
+
+        std::unique_ptr<LayoutWidget> layout(new LayoutWidget);
+        layout->SetPadding(10);
+        layout->SetBackgroundCleared(true);
+        layout->AddWidget(new TestCairoWidget(parameters["animate"].as<bool>()));
+        layout->AddWidget(new TestWorldSceneWidget(parameters["animate"].as<bool>()));
+
+        context_->SetCentralWidget(layout.release());
+        context_->SetUpdateDelay(25);  // If animation, update the content each 25ms
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/index.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,23 @@
+<!doctype html>
+
+<html lang="us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+    <!-- Disable pinch zoom on mobile devices -->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="HandheldFriendly" content="true" />
+
+    <title>Wasm Samples</title>
+
+<body>
+    <ul>
+      <li><a href="simple-viewer/simple-viewer.html">Simple Viewer Project (you may add ?studyId=XXX in the url)</a></li>
+      <li><a href="single-frame.html?instance=XXX">Single frame application (you must replace XXX by a valid instance id in the url)</a></li>
+      <li><a href="single-frame-editor.html?instance=XXX">Single frame editor application (you must replace XXX by a valid instance id in the url)</a></li>
+      <li><a href="simple-viewer-single-file.html">Simple Viewer Single file (to be replaced by other samples)</a></li>
+    </ul>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/samples-styles.css	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,16 @@
+html, body {
+  width: 100%;
+  height: 100%;
+  margin: 0px;
+  border: 0;
+  overflow: hidden; /*  Disable scrollbars */
+  display: block;  /* No floating content on sides */
+  background-color: black;
+  color: white;
+  font-family: Arial, Helvetica, sans-serif;
+}
+
+canvas {
+  left:0px;
+  top:0px;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/simple-viewer-single-file.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,39 @@
+<!doctype html>
+
+<html lang="us">
+
+<head>
+  <meta charset="utf-8" />
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+  <!-- Disable pinch zoom on mobile devices -->
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+  <meta name="HandheldFriendly" content="true" />
+
+  <title>Simple Viewer</title>
+  <link href="samples-styles.css" rel="stylesheet" />
+
+<body>
+  <div id="breadcrumb">
+    <span id="patient-id"></span>
+    <span id="study-description"></span>
+    <span id="series-description"></span>
+  </div>
+  <div style="height: calc(100% - 50px)">
+    <div style="width: 20%; height: 100%; display: inline-block">
+      <canvas id="canvas"></canvas>
+    </div>
+    <div style="width: 70%; height: 100%; display: inline-block">
+      <canvas id="canvas2"></canvas>
+    </div>
+  </div>
+  <div id="toolbox" style="height: 50px">
+    <input tool-selector="line-measure" type="radio" name="radio-tool-selector" class="tool-selector">line
+    <input tool-selector="circle-measure" type="radio" name="radio-tool-selector" class="tool-selector">circle
+    <button action-trigger="action1" class="action-trigger">action1</button>
+    <button action-trigger="action2" class="action-trigger">action2</button>
+  </div>
+  <script type="text/javascript" src="app-simple-viewer-single-file.js"></script>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/simple-viewer-single-file.ts	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,61 @@
+import wasmApplicationRunner = require('../../../Platforms/Wasm/wasm-application-runner');
+
+wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSimpleViewerSingleFile", "/orthanc");
+
+function SelectTool(toolName: string) {
+    var command = {
+        command: "selectTool",
+        args: {
+            toolName: toolName
+        }
+    };
+    wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
+
+}
+
+function PerformAction(commandName: string) {
+    var command = {
+        command: commandName,
+        commandType: "simple",
+        args: {}
+    };
+    wasmApplicationRunner.SendSerializedMessageToStoneApplication(JSON.stringify(command));
+}
+
+//initializes the buttons
+//-----------------------
+// install "SelectTool" handlers
+document.querySelectorAll("[tool-selector]").forEach((e) => {
+    console.log(e);
+    (e as HTMLInputElement).addEventListener("click", () => {
+        console.log(e);
+        SelectTool(e.attributes["tool-selector"].value);
+    });
+});
+
+// install "PerformAction" handlers
+document.querySelectorAll("[action-trigger]").forEach((e) => {
+    (e as HTMLInputElement).addEventListener("click", () => {
+        PerformAction(e.attributes["action-trigger"].value);
+    });
+});
+
+// this method is called "from the C++ code" when the StoneApplication is updated.
+// it can be used to update the UI of the application
+function UpdateWebApplicationWithString(statusUpdateMessage: string) {
+  console.log(statusUpdateMessage);
+  
+  if (statusUpdateMessage.startsWith("series-description=")) {
+      document.getElementById("series-description").innerText = statusUpdateMessage.split("=")[1];
+  }
+}
+
+function UpdateWebApplicationWithSerializedMessage(statusUpdateMessageString: string) {
+  console.log("updating web application with serialized message: ", statusUpdateMessageString);
+  console.log("<not supported in the simple viewer (single file)!>");
+}
+
+// make it available to other js scripts in the application
+(<any> window).UpdateWebApplicationWithString = UpdateWebApplicationWithString;
+
+(<any> window).UpdateWebApplicationWithSerializedMessage = UpdateWebApplicationWithSerializedMessage;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/simple-viewer-single-file.tsconfig.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,9 @@
+{
+    "extends" : "./tsconfig-samples",
+    "compilerOptions": {
+        // "outFile": "../build-web/app-simple-viewer-single-file.js"
+    },
+    "include" : [
+        "simple-viewer-single-file.ts"
+    ]
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/single-frame-editor.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,22 @@
+<!doctype html>
+
+<html lang="us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+    <!-- Disable pinch zoom on mobile devices -->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="HandheldFriendly" content="true" />
+
+    <title>Simple Viewer</title>
+    <link href="samples-styles.css" rel="stylesheet" />
+
+<body>
+  <div style="width: 100%; height: 100%">
+    <canvas id="canvas"></canvas>
+  </div>
+  <script type="text/javascript" src="app-single-frame-editor.js"></script>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/single-frame-editor.ts	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,3 @@
+import wasmApplicationRunner = require('../../../Platforms/Wasm/wasm-application-runner');
+
+wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSingleFrameEditor", "/orthanc");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/single-frame-editor.tsconfig.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,8 @@
+{
+    "extends" : "./tsconfig-samples",
+    "compilerOptions": {
+    },
+    "include" : [
+        "single-frame-editor.ts"
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/single-frame.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,22 @@
+<!doctype html>
+
+<html lang="us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+    <!-- Disable pinch zoom on mobile devices -->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="HandheldFriendly" content="true" />
+
+    <title>Simple Viewer</title>
+    <link href="samples-styles.css" rel="stylesheet" />
+
+<body>
+  <div style="width: 100%; height: 100%">
+    <canvas id="canvas"></canvas>
+  </div>
+  <script type="text/javascript" src="app-single-frame.js"></script>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/single-frame.ts	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,4 @@
+import wasmApplicationRunner = require('../../../Platforms/Wasm/wasm-application-runner');
+
+wasmApplicationRunner.InitializeWasmApplication("OrthancStoneSingleFrame", "/orthanc");
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/single-frame.tsconfig.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,8 @@
+{
+    "extends" : "./tsconfig-samples",
+    "compilerOptions": {
+    },
+    "include" : [
+        "single-frame.ts"
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/Web/tsconfig-samples.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,11 @@
+{
+    "extends" : "../../../Platforms/Wasm/tsconfig-stone",
+    "compilerOptions": {
+        "sourceMap": false,
+        "lib" : [
+            "es2017",
+            "dom",
+            "dom.iterable"
+        ]
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/build-wasm.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# usage:
+# to build all targets in Debug:
+# ./build-wasm.sh
+#
+# to build a single target in release:
+# ./build-wasm.sh OrthancStoneSingleFrameEditor Release
+
+set -e
+
+target=${1:-all}
+buildType=${2:-Debug}
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+mkdir -p $samplesRootDir/build-wasm
+cd $samplesRootDir/build-wasm
+
+source ~/apps/emsdk/emsdk_env.sh
+cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=~/apps/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=$buildType -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
+ninja $target
+
+echo "-- building the web application -- "
+cd $currentDir
+./build-web.sh
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/build-wasm.sh.old	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# usage:
+# to build all targets:
+# ./build-wasm.sh
+#
+# to build a single target:
+# ./build-wasm.sh OrthancStoneSingleFrameEditor
+
+set -e
+
+target=${1:-all}
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+mkdir -p $samplesRootDir/build-wasm
+cd $samplesRootDir/build-wasm
+
+source ~/apps/emsdk/emsdk_env.sh
+cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone \
+  -DORTHANC_FRAMEWORK_SOURCE=path \
+  -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc \
+  -DALLOW_DOWNLOADS=ON .. \
+  -DENABLE_WASM=ON
+
+ninja $target
+
+echo "-- building the web application -- "
+cd $currentDir
+./build-web.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/build-web-ext.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+set -e
+
+target=${1:-all}
+# this script currently assumes that the wasm code has been built on its side and is availabie in build-wasm/
+
+currentDir=$(pwd)
+
+scriptDirRel=$(dirname $0)
+#echo $scriptDirRel
+scriptDirAbs=$(realpath $scriptDirRel)
+echo $scriptDirAbs
+
+samplesRootDir=scriptDirAbs
+
+outputDir=$samplesRootDir/build-web/
+mkdir -p $outputDir
+
+# files used by all single files samples
+cp $samplesRootDir/Web/index.html $outputDir
+cp $samplesRootDir/Web/samples-styles.css $outputDir
+
+# build simple-viewer-single-file (obsolete project)
+if [[ $target == "all" || $target == "OrthancStoneSimpleViewerSingleFile" ]]; then
+  cp $samplesRootDir/Web/simple-viewer-single-file.html $outputDir
+  tsc --allowJs --project $samplesRootDir/Web/simple-viewer-single-file.tsconfig.json
+  cp $currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.js  $outputDir
+  cp $currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.wasm  $outputDir
+fi
+
+# build single-frame
+if [[ $target == "all" || $target == "OrthancStoneSingleFrame" ]]; then
+  cp $samplesRootDir/Web/single-frame.html $outputDir
+  tsc --allowJs --project $samplesRootDir/Web/single-frame.tsconfig.json
+  cp $currentDir/build-wasm/OrthancStoneSingleFrame.js  $outputDir
+  cp $currentDir/build-wasm/OrthancStoneSingleFrame.wasm  $outputDir
+fi
+
+# build single-frame-editor
+if [[ $target == "all" || $target == "OrthancStoneSingleFrameEditor" ]]; then
+  cp $samplesRootDir/Web/single-frame-editor.html $outputDir
+  tsc --allowJs --project $samplesRootDir/Web/single-frame-editor.tsconfig.json
+  cp $currentDir/build-wasm/OrthancStoneSingleFrameEditor.js  $outputDir
+  cp $currentDir/build-wasm/OrthancStoneSingleFrameEditor.wasm  $outputDir
+fi
+
+# build simple-viewer project
+if [[ $target == "all" || $target == "OrthancStoneSimpleViewer" ]]; then
+  mkdir -p $outputDir/simple-viewer/
+  cp $samplesRootDir/SimpleViewer/Wasm/simple-viewer.html $outputDir/simple-viewer/
+  cp $samplesRootDir/SimpleViewer/Wasm/styles.css $outputDir/simple-viewer/
+  tsc --allowJs --project $samplesRootDir/SimpleViewer/Wasm/tsconfig-simple-viewer.json
+  cp $currentDir/build-wasm/OrthancStoneSimpleViewer.js  $outputDir/simple-viewer/
+  cp $currentDir/build-wasm/OrthancStoneSimpleViewer.wasm  $outputDir/simple-viewer/
+fi
+
+cd $currentDir
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/build-web.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+set -e
+
+target=${1:-all}
+# this script currently assumes that the wasm code has been built on its side and is availabie in build-wasm/
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+echo "*************************************************************************"
+echo "samplesRootDir = $samplesRootDir"
+echo "*************************************************************************"
+
+outputDir=$samplesRootDir/build-web/
+mkdir -p "$outputDir"
+
+# files used by all single files samples
+cp "$samplesRootDir/Web/index.html" "$outputDir"
+cp "$samplesRootDir/Web/samples-styles.css" "$outputDir"
+
+# # build simple-viewer-single-file (obsolete project)
+# if [[ $target == "all" || $target == "OrthancStoneSimpleViewerSingleFile" ]]; then
+#   cp $samplesRootDir/Web/simple-viewer-single-file.html $outputDir
+#   tsc --project $samplesRootDir/Web/simple-viewer-single-file.tsconfig.json --outDir "$outputDir"
+#   browserify \
+#       "$outputDir/Platforms/Wasm/wasm-application-runner.js" \
+#       "$outputDir/Applications/Samples/Web/simple-viewer-single-file.js" \
+#       -o "$outputDir/app-simple-viewer-single-file.js"
+#   cp "$currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.js"  $outputDir
+#   cp "$currentDir/build-wasm/OrthancStoneSimpleViewerSingleFile.wasm"  $outputDir
+# fi
+
+# # build single-frame
+# if [[ $target == "all" || $target == "OrthancStoneSingleFrame" ]]; then
+#   cp $samplesRootDir/Web/single-frame.html $outputDir
+#   tsc --project $samplesRootDir/Web/single-frame.tsconfig.json --outDir "$outputDir"
+#   browserify \
+#       "$outputDir/Platforms/Wasm/wasm-application-runner.js" \
+#       "$outputDir/Applications/Samples/Web/single-frame.js" \
+#       -o "$outputDir/app-single-frame.js"
+#   cp "$currentDir/build-wasm/OrthancStoneSingleFrame.js"  $outputDir
+#   cp "$currentDir/build-wasm/OrthancStoneSingleFrame.wasm"  $outputDir
+# fi
+
+# build single-frame-editor
+if [[ $target == "all" || $target == "OrthancStoneSingleFrameEditor" ]]; then
+  cp $samplesRootDir/Web/single-frame-editor.html $outputDir
+  tsc --project $samplesRootDir/Web/single-frame-editor.tsconfig.json --outDir "$outputDir"
+  browserify \
+      "$outputDir/Platforms/Wasm/wasm-application-runner.js" \
+      "$outputDir/Applications/Samples/Web/single-frame-editor.js" \
+      -o "$outputDir/app-single-frame-editor.js"
+  cp "$currentDir/build-wasm/OrthancStoneSingleFrameEditor.js"  $outputDir
+  cp "$currentDir/build-wasm/OrthancStoneSingleFrameEditor.wasm"  $outputDir
+fi
+
+# build simple-viewer project
+if [[ $target == "all" || $target == "OrthancStoneSimpleViewer" ]]; then
+  mkdir -p $outputDir/simple-viewer/
+  cp $samplesRootDir/SimpleViewer/Wasm/simple-viewer.html $outputDir/simple-viewer/
+  cp $samplesRootDir/SimpleViewer/Wasm/styles.css $outputDir/simple-viewer/
+  
+  # the root dir must contain all the source files for the whole project
+  tsc --module commonjs --allowJs --project "$samplesRootDir/SimpleViewer/Wasm/tsconfig-simple-viewer.json" --rootDir "$samplesRootDir/../.." --outDir "$outputDir/simple-viewer/"
+  browserify \
+    "$outputDir/simple-viewer/Platforms/Wasm/wasm-application-runner.js" \
+    "$outputDir/simple-viewer/Applications/Samples/SimpleViewer/Wasm/simple-viewer.js" \
+    -o "$outputDir/simple-viewer/app-simple-viewer.js"
+  cp "$currentDir/build-wasm/OrthancStoneSimpleViewer.js"  "$outputDir/simple-viewer/"
+  cp "$currentDir/build-wasm/OrthancStoneSimpleViewer.wasm"  "$outputDir/simple-viewer/"
+fi
+
+cd $currentDir
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/get-requirements-windows.ps1	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,50 @@
+
+if ($true) {
+
+    Write-Error "This script is obsolete. Please work under WSL and run build-wasm.sh"
+
+} else {
+
+    param(
+        [IO.DirectoryInfo] $EmsdkRootDir = "C:\Emscripten",
+        [bool] $Overwrite = $false
+      )
+    
+    if (Test-Path -Path $EmsdkRootDir) {
+        if( $Override) {
+            Remove-Item -Path $EmsdkRootDir -Force -Recurse
+        } else {
+            throw "The `"$EmsdkRootDir`" folder may not exist! Use the Overwrite flag to bypass this check."
+        }
+    }
+    
+    # TODO: detect whether git is installed
+    # choco install -y git
+    
+    Write-Host "Will retrieve the Emscripten SDK to the `"$EmsdkRootDir`" folder"
+    
+    $EmsdkParentDir = split-path -Parent $EmsdkRootDir
+    $EmsdkRootName = split-path -Leaf $EmsdkRootDir
+    
+    Push-Location $EmsdkParentDir
+    
+    git clone https://github.com/juj/emsdk.git $EmsdkRootName
+    cd $EmsdkRootName
+    
+    git pull
+    
+    ./emsdk install latest
+    
+    ./emsdk activate latest
+    
+    echo "INFO: the ~/.emscripten file has been configured for this installation of Emscripten."
+    
+    Write-Host "emsdk is now installed in $EmsdkRootDir"
+    
+    Pop-Location
+
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/nginx.local.conf	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,44 @@
+# Local config to serve the WASM samples static files and reverse proxy Orthanc.
+# Uses port 9977 instead of 80.
+
+# `events` section is mandatory
+events {
+  worker_connections 1024; # Default: 1024
+}
+
+http {
+
+  # prevent nginx sync issues on OSX
+  proxy_buffering off;
+
+  server {
+    listen 9977 default_server;
+    client_max_body_size 4G;
+
+    # location may have to be adjusted depending on your OS and nginx install
+    include /etc/nginx/mime.types;
+    # if not in your system mime.types, add this line to support WASM:
+    # types {
+    #    application/wasm                      wasm; 
+    # }
+
+    # serve WASM static files
+    root build-web/;
+    location / {
+	}
+
+    # reverse proxy orthanc
+	location /orthanc/ {
+		rewrite /orthanc(.*) $1 break;
+		proxy_pass http://127.0.0.1:8042;
+		proxy_set_header Host $http_host;
+		proxy_set_header my-auth-header good-token;
+		proxy_request_buffering off;
+		proxy_max_temp_file_size 0;
+		client_max_body_size 0;
+	}
+
+
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/package-lock.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,11 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "typescript": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz",
+      "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg=="
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/CMakeLists.txt	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,142 @@
+cmake_minimum_required(VERSION 2.8.3)
+project(RtViewerDemo)
+
+if(MSVC)
+  add_definitions(/MP)
+  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
+    add_definitions(/JMC)
+  endif()
+endif()
+
+message("-------------------------------------------------------------------------------------------------------------------")
+message("ORTHANC_FRAMEWORK_ROOT is set to ${ORTHANC_FRAMEWORK_ROOT}")
+message("-------------------------------------------------------------------------------------------------------------------")
+
+if(NOT DEFINED ORTHANC_FRAMEWORK_ROOT)
+  message(FATAL_ERROR "The location of the Orthanc source repository must be set in the ORTHANC_FRAMEWORK_ROOT CMake variable")
+endif()
+
+message("-------------------------------------------------------------------------------------------------------------------")
+message("STONE_SOURCES_DIR is set to ${STONE_SOURCES_DIR}")
+message("-------------------------------------------------------------------------------------------------------------------")
+
+if(NOT DEFINED STONE_SOURCES_DIR)
+  message(FATAL_ERROR "The location of the Stone of Orthanc source repository must be set in the STONE_SOURCES_DIR CMake variable")
+endif()
+
+include(${STONE_SOURCES_DIR}/Resources/CMake/OrthancStoneParameters.cmake)
+
+if (OPENSSL_NO_CAPIENG)
+add_definitions(-DOPENSSL_NO_CAPIENG=1)
+endif()
+
+set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
+set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
+set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
+
+if (ENABLE_WASM)
+  #####################################################################
+  ## Configuration of the Emscripten compiler for WebAssembly target
+  #####################################################################
+
+  set(WASM_FLAGS "-s WASM=1")
+  set(WASM_FLAGS "${WASM_FLAGS} -s STRICT=1") # drops support for all deprecated build options
+  set(WASM_FLAGS "${WASM_FLAGS} -s FILESYSTEM=1") # if we don't include it, gen_uuid.c fails to build because srand, getpid(), ... are not defined
+  set(WASM_FLAGS "${WASM_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0") # actually enable exception catching 
+  set(WASM_FLAGS "${WASM_FLAGS} -s ERROR_ON_MISSING_LIBRARIES=1")
+
+  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
+    set(WASM_FLAGS "${WASM_FLAGS} -g4") # generate debug information
+    set(WASM_FLAGS "${WASM_FLAGS} -s ASSERTIONS=2") # more runtime checks
+  else()
+    set(WASM_FLAGS "${WASM_FLAGS} -Os") # optimize for web (speed and size)
+  endif()
+
+  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
+
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
+
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_FLAGS}")  # not always clear which flags are for the compiler and which one are for the linker -> pass them all to the linker too
+  # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"'")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=128000000")
+
+  add_definitions(-DORTHANC_ENABLE_WASM=1)
+  set(ORTHANC_SANDBOXED ON)
+
+elseif (ENABLE_QT OR ENABLE_SDL)
+
+  set(ENABLE_NATIVE ON)
+  set(ORTHANC_SANDBOXED OFF)
+  set(ENABLE_CRYPTO_OPTIONS ON)
+  set(ENABLE_GOOGLE_TEST ON)
+  set(ENABLE_WEB_CLIENT ON)
+
+endif()
+
+
+#####################################################################
+## Configuration for Orthanc
+#####################################################################
+
+if (ORTHANC_STONE_VERSION STREQUAL "mainline")
+  set(ORTHANC_FRAMEWORK_VERSION "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
+else()
+  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
+endif()
+
+set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
+set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
+set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
+
+add_definitions(
+  -DORTHANC_ENABLE_LOGGING_PLUGIN=0
+  )
+
+
+#####################################################################
+## Build a static library containing the Orthanc Stone framework
+#####################################################################
+
+LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
+
+include(${STONE_SOURCES_DIR}/Resources/CMake/OrthancStoneConfiguration.cmake)
+
+add_library(OrthancStone STATIC
+  ${ORTHANC_STONE_SOURCES}
+  )
+
+#####################################################################
+## Build all the sample applications
+#####################################################################
+
+include_directories(${ORTHANC_STONE_ROOT})
+
+list(APPEND RTVIEWERDEMO_APPLICATION_SOURCES
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
+  )
+
+if (ENABLE_WASM)
+  list(APPEND RTVIEWERDEMO_APPLICATION_SOURCES
+    ${STONE_WASM_SOURCES}
+    )
+endif()
+
+add_executable(RtViewerDemo
+  main.cpp
+  ${RTVIEWERDEMO_APPLICATION_SOURCES}
+)
+set_target_properties(RtViewerDemo PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=3)
+target_include_directories(RtViewerDemo PRIVATE ${ORTHANC_STONE_ROOT})
+target_link_libraries(RtViewerDemo OrthancStone)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/build-sdl-msvc15.ps1	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,24 @@
+if (-not (Test-Path "build-sdl-msvc15")) {
+  mkdir -p "build-sdl-msvc15"
+}
+
+cd build-sdl-msvc15
+
+cmake -G "Visual Studio 15 2017 Win64" -DSTATIC_BUILD=ON -DOPENSSL_NO_CAPIENG=ON -DORTHANC_FRAMEWORK_SOURCE=path -DSTONE_SOURCES_DIR="$($pwd)\..\..\..\.." -DORTHANC_FRAMEWORK_ROOT="$($pwd)\..\..\..\..\..\orthanc" -DALLOW_DOWNLOADS=ON -DENABLE_SDL=ON .. 
+
+if (!$?) {
+	Write-Error 'cmake configuration failed' -ErrorAction Stop
+}
+
+cmake --build . --target RtViewerDemo --config Debug
+
+if (!$?) {
+	Write-Error 'cmake build failed' -ErrorAction Stop
+}
+
+cd Debug
+
+.\RtViewerDemo.exe --ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa --dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb --struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/build-wasm.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+# usage:
+# build-wasm BUILD_TYPE
+# where BUILD_TYPE is Debug, RelWithDebInfo or Release
+
+set -e
+
+buildType=${1:-Debug}
+
+currentDir=$(pwd)
+currentDirAbs=$(realpath $currentDir)
+
+mkdir -p build-wasm
+cd build-wasm
+
+source ~/apps/emsdk/emsdk_env.sh
+cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake \
+-DCMAKE_BUILD_TYPE=$buildType -DSTONE_SOURCES_DIR=$currentDirAbs/../../../../orthanc-stone \
+-DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDirAbs/../../../../orthanc \
+-DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
+
+ninja $target
+
+echo "-- building the web application -- "
+cd $currentDir
+./build-web.sh
+
+echo "Launch start-serving-files.sh to access the web sample application locally"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/build-web.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+set -e
+
+target=${1:-all}
+# this script currently assumes that the wasm code has been built on its side and is availabie in build-wasm/
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+tscOutput=$samplesRootDir/build-tsc-output/
+outputDir=$samplesRootDir/build-web/
+mkdir -p "$outputDir"
+
+# files used by all single files samples
+cp "$samplesRootDir/index.html" "$outputDir"
+cp "$samplesRootDir/samples-styles.css" "$outputDir"
+
+# build rt-viewer-demo
+cp $samplesRootDir/rt-viewer-demo.html $outputDir
+tsc --project $samplesRootDir/rt-viewer-demo.tsconfig.json --outDir "$tscOutput"
+browserify \
+    "$tscOutput/orthanc-stone/Platforms/Wasm/logger.js" \
+    "$tscOutput/orthanc-stone/Platforms/Wasm/stone-framework-loader.js" \
+    "$tscOutput/orthanc-stone/Platforms/Wasm/wasm-application-runner.js" \
+    "$tscOutput/orthanc-stone/Platforms/Wasm/wasm-viewport.js" \
+    "$tscOutput/rt-viewer-sample/rt-viewer-demo.js" \
+    -o "$outputDir/app-rt-viewer-demo.js"
+cp "$currentDir/build-wasm/RtViewerDemo.js"  $outputDir
+cp "$currentDir/build-wasm/RtViewerDemo.wasm"  $outputDir
+
+cd $currentDir
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/index.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,20 @@
+<!doctype html>
+
+<html lang="us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+    <!-- Disable pinch zoom on mobile devices -->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="HandheldFriendly" content="true" />
+
+    <title>Wasm Samples</title>
+
+<body>
+    <ul>
+      <li><a href="rt-viewer-demo.html?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa&dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb&struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9">RTSTRUCT + CT + RTDOSE viewer demo. Pplease replace the url arguments with suitable IDs (you can find those in the Orthanc Explorer, for instance)</a></li>
+    </ul>
+</body>
+
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/main.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,893 @@
+/**
+ * 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 "Applications/IStoneApplication.h"
+#include "Framework/Widgets/WorldSceneWidget.h"
+#include "Framework/Widgets/LayoutWidget.h"
+
+#if ORTHANC_ENABLE_WASM==1
+  #include "Platforms/Wasm/WasmPlatformApplicationAdapter.h"
+  #include "Platforms/Wasm/Defaults.h"
+  #include "Platforms/Wasm/WasmViewport.h"
+#endif
+
+#if ORTHANC_ENABLE_QT==1
+  #include "Qt/SampleMainWindow.h"
+  #include "Qt/SampleMainWindowWithButtons.h"
+#endif
+
+#include "Framework/Layers/DicomSeriesVolumeSlicer.h"
+#include "Framework/Widgets/SliceViewerWidget.h"
+#include "Framework/Volumes/StructureSetLoader.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <Core/Images/ImageTraits.h>
+
+#include <boost/math/constants/constants.hpp>
+#include "Framework/dev.h"
+#include "Framework/Widgets/LayoutWidget.h"
+#include "Framework/Layers/DicomStructureSetSlicer.h"
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    class RtViewerDemoBaseApplication : public IStoneApplication
+    {
+    protected:
+      // ownership is transferred to the application context
+#ifndef RESTORE_NON_RTVIEWERDEMO_BEHAVIOR
+      LayoutWidget*          mainWidget_;
+#else
+      WorldSceneWidget*  mainWidget_;
+#endif
+
+    public:
+      virtual void Initialize(StoneApplicationContext* context,
+                              IStatusBar& statusBar,
+                              const boost::program_options::variables_map& parameters) ORTHANC_OVERRIDE
+      {
+      }
+
+      virtual std::string GetTitle() const ORTHANC_OVERRIDE
+      {
+        return "Stone of Orthanc - Sample";
+      }
+
+      /**
+       * In the basic samples, the commands are handled by the platform adapter and NOT
+       * by the application handler
+      */
+      virtual void HandleSerializedMessage(const char* data) ORTHANC_OVERRIDE {};
+
+
+      virtual void Finalize() ORTHANC_OVERRIDE {}
+      virtual IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainWidget_;}
+
+#if ORTHANC_ENABLE_WASM==1
+      // default implementations for a single canvas named "canvas" in the HTML and an empty WasmApplicationAdapter
+
+      virtual void InitializeWasm() ORTHANC_OVERRIDE
+      {
+        AttachWidgetToWasmViewport("canvas", mainWidget_);
+      }
+
+      virtual WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(MessageBroker& broker)
+      {
+        return new WasmPlatformApplicationAdapter(broker, *this);
+      }
+#endif
+
+    };
+
+    // this application actually works in Qt and WASM
+    class RtViewerDemoBaseSingleCanvasWithButtonsApplication : public RtViewerDemoBaseApplication
+    {
+public:
+      virtual void OnPushButton1Clicked() {}
+      virtual void OnPushButton2Clicked() {}
+      virtual void OnTool1Clicked() {}
+      virtual void OnTool2Clicked() {}
+
+      virtual void GetButtonNames(std::string& pushButton1,
+                                  std::string& pushButton2,
+                                  std::string& tool1,
+                                  std::string& tool2
+                                  ) {
+        pushButton1 = "action1";
+        pushButton2 = "action2";
+        tool1 = "tool1";
+        tool2 = "tool2";
+      }
+
+#if ORTHANC_ENABLE_QT==1
+      virtual QStoneMainWindow* CreateQtMainWindow() {
+        return new SampleMainWindowWithButtons(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
+      }
+#endif
+
+    };
+
+    // this application actually works in SDL and WASM
+    class RtViewerDemoBaseApplicationSingleCanvas : public RtViewerDemoBaseApplication
+    {
+public:
+
+#if ORTHANC_ENABLE_QT==1
+      virtual QStoneMainWindow* CreateQtMainWindow() {
+        return new SampleMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this);
+      }
+#endif
+    };
+  }
+}
+
+
+
+namespace OrthancStone
+{
+  namespace Samples
+  {
+    template <Orthanc::PixelFormat T>
+    void ReadDistributionInternal(std::vector<float>& distribution,
+                                  const Orthanc::ImageAccessor& image)
+    {
+      const unsigned int width = image.GetWidth();
+      const unsigned int height = image.GetHeight();
+      
+      distribution.resize(width * height);
+      size_t pos = 0;
+
+      for (unsigned int y = 0; y < height; y++)
+      {
+        for (unsigned int x = 0; x < width; x++, pos++)
+        {
+          distribution[pos] = Orthanc::ImageTraits<T>::GetFloatPixel(image, x, y);
+        }
+      }
+    }
+
+    void ReadDistribution(std::vector<float>& distribution,
+                          const Orthanc::ImageAccessor& image)
+    {
+      switch (image.GetFormat())
+      {
+        case Orthanc::PixelFormat_Grayscale8:
+          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale8>(distribution, image);
+          break;
+
+        case Orthanc::PixelFormat_Grayscale16:
+          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale16>(distribution, image);
+          break;
+
+        case Orthanc::PixelFormat_SignedGrayscale16:
+          ReadDistributionInternal<Orthanc::PixelFormat_SignedGrayscale16>(distribution, image);
+          break;
+
+        case Orthanc::PixelFormat_Grayscale32:
+          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale32>(distribution, image);
+          break;
+
+        case Orthanc::PixelFormat_Grayscale64:
+          ReadDistributionInternal<Orthanc::PixelFormat_Grayscale64>(distribution, image);
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      }
+    }
+
+
+    class DoseInteractor : public VolumeImageInteractor
+    {
+    private:
+      SliceViewerWidget&         widget_;
+      size_t               layer_;
+      DicomFrameConverter  converter_;
+
+
+      
+    protected:
+      virtual void NotifySliceChange(const ISlicedVolume& slicedVolume,
+                                    const size_t& sliceIndex,
+                                    const Slice& slice)
+      {
+        converter_ = slice.GetConverter();
+        
+  #if 0
+        const OrthancVolumeImage& volume = dynamic_cast<const OrthancVolumeImage&>(slicedVolume);
+
+        RenderStyle s = widget_.GetLayerStyle(layer_);
+
+        if (volume.FitWindowingToRange(s, slice.GetConverter()))
+        {
+          printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
+          widget_.SetLayerStyle(layer_, s);
+        }
+  #endif
+      }
+
+      virtual void NotifyVolumeReady(const ISlicedVolume& slicedVolume)
+      {
+        const float percentile = 0.01f;
+        const OrthancVolumeImage& volume = dynamic_cast<const OrthancVolumeImage&>(slicedVolume);
+
+        std::vector<float> distribution;
+        ReadDistribution(distribution, volume.GetImage().GetInternalImage());
+        std::sort(distribution.begin(), distribution.end());
+
+        int start = static_cast<int>(std::ceil(distribution.size() * percentile));
+        int end = static_cast<int>(std::floor(distribution.size() * (1.0f - percentile)));
+
+        float a = 0;
+        float b = 0;
+        
+        if (start < end &&
+            start >= 0 &&
+            end < static_cast<int>(distribution.size()))
+        {
+          a = distribution[start];
+          b = distribution[end];
+        }
+        else if (!distribution.empty())
+        {
+          // Too small distribution: Use full range
+          a = distribution.front();
+          b = distribution.back();
+        }
+
+        //printf("%f %f\n", a, b);
+
+        RenderStyle s = widget_.GetLayerStyle(layer_);
+        s.windowing_ = ImageWindowing_Custom;
+        s.customWindowCenter_ = static_cast<float>(converter_.Apply((a + b) / 2.0f));
+        s.customWindowWidth_ = static_cast<float>(converter_.Apply(b - a));
+        
+        // 96.210556 => 192.421112
+        widget_.SetLayerStyle(layer_, s);
+        printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);      
+      }
+
+    public:
+      DoseInteractor(MessageBroker& broker, OrthancVolumeImage& volume,
+                    SliceViewerWidget& widget,
+                    VolumeProjection projection,
+                    size_t layer) :
+        VolumeImageInteractor(broker, volume, widget, projection),
+        widget_(widget),
+        layer_(layer)
+      {
+      }
+    };
+
+    class RtViewerDemoApplication :
+      public RtViewerDemoBaseApplicationSingleCanvas,
+      public IObserver
+    {
+    public:
+      std::vector<std::pair<SliceViewerWidget*, size_t> > doseCtWidgetLayerPairs_;
+      std::list<OrthancStone::IWorldSceneInteractor*>    interactors_;
+
+      class Interactor : public IWorldSceneInteractor
+      {
+      private:
+        RtViewerDemoApplication&  application_;
+
+      public:
+        Interactor(RtViewerDemoApplication&  application) :
+          application_(application)
+        {
+        }
+
+        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+          const ViewportGeometry& view,
+          MouseButton button,
+          KeyboardModifiers modifiers,
+          int viewportX,
+          int viewportY,
+          double x,
+          double y,
+          IStatusBar* statusBar,
+          const std::vector<Touch>& displayTouches)
+        {
+          return NULL;
+        }
+
+        virtual void MouseOver(CairoContext& context,
+          WorldSceneWidget& widget,
+          const ViewportGeometry& view,
+          double x,
+          double y,
+          IStatusBar* statusBar)
+        {
+          if (statusBar != NULL)
+          {
+            Vector p = dynamic_cast<SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y);
+
+            char buf[64];
+            sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)",
+              p[0] / 10.0, p[1] / 10.0, p[2] / 10.0);
+            statusBar->SetMessage(buf);
+          }
+        }
+
+        virtual void MouseWheel(WorldSceneWidget& widget,
+          MouseWheelDirection direction,
+          KeyboardModifiers modifiers,
+          IStatusBar* statusBar)
+        {
+          int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
+
+          switch (direction)
+          {
+          case MouseWheelDirection_Up:
+            application_.OffsetSlice(-scale);
+            break;
+
+          case MouseWheelDirection_Down:
+            application_.OffsetSlice(scale);
+            break;
+
+          default:
+            break;
+          }
+        }
+
+        virtual void KeyPressed(WorldSceneWidget& widget,
+          KeyboardKeys key,
+          char keyChar,
+          KeyboardModifiers modifiers,
+          IStatusBar* statusBar)
+        {
+          switch (keyChar)
+          {
+          case 's':
+            // TODO: recursively traverse children
+            widget.FitContent();
+            break;
+
+          default:
+            break;
+          }
+        }
+      };
+
+      void OffsetSlice(int offset)
+      {
+        if (source_ != NULL)
+        {
+          int slice = static_cast<int>(slice_) + offset;
+
+          if (slice < 0)
+          {
+            slice = 0;
+          }
+
+          if (slice >= static_cast<int>(source_->GetSliceCount()))
+          {
+            slice = static_cast<int>(source_->GetSliceCount()) - 1;
+          }
+
+          if (slice != static_cast<int>(slice_))
+          {
+            SetSlice(slice);
+          }
+        }
+      }
+
+
+      SliceViewerWidget& GetMainWidget()
+      {
+        return *dynamic_cast<SliceViewerWidget*>(mainWidget_);
+      }
+
+
+      void SetSlice(size_t index)
+      {
+        if (source_ != NULL &&
+          index < source_->GetSliceCount())
+        {
+          slice_ = static_cast<unsigned int>(index);
+
+#if 1
+          GetMainWidget().SetSlice(source_->GetSlice(slice_).GetGeometry());
+#else
+          // TEST for scene extents - Rotate the axes
+          double a = 15.0 / 180.0 * boost::math::constants::pi<double>();
+
+#if 1
+          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
+          Vector y; GeometryToolbox::AssignVector(y, -sin(a), cos(a), 0);
+#else
+          // Flip the normal
+          Vector x; GeometryToolbox::AssignVector(x, cos(a), sin(a), 0);
+          Vector y; GeometryToolbox::AssignVector(y, sin(a), -cos(a), 0);
+#endif
+
+          SliceGeometry s(source_->GetSlice(slice_).GetGeometry().GetOrigin(), x, y);
+          widget_->SetSlice(s);
+#endif
+        }
+      }
+
+
+      void OnMainWidgetGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
+      {
+        // Once the geometry of the series is downloaded from Orthanc,
+        // display its middle slice, and adapt the viewport to fit this
+        // slice
+        if (source_ == &message.GetOrigin())
+        {
+          SetSlice(source_->GetSliceCount() / 2);
+        }
+
+        GetMainWidget().FitContent();
+      }
+
+    DicomFrameConverter                                converter_;
+
+    void OnSliceContentChangedMessage(const ISlicedVolume::SliceContentChangedMessage&   message)
+    {
+      converter_ = message.GetSlice().GetConverter();
+    }
+
+    void OnVolumeReadyMessage(const ISlicedVolume::VolumeReadyMessage& message)
+    {
+      const float percentile = 0.01f;
+
+      auto& slicedVolume = message.GetOrigin();
+      const OrthancVolumeImage& volume = dynamic_cast<const OrthancVolumeImage&>(slicedVolume);
+
+      std::vector<float> distribution;
+      ReadDistribution(distribution, volume.GetImage().GetInternalImage());
+      std::sort(distribution.begin(), distribution.end());
+
+      int start = static_cast<int>(std::ceil(distribution.size() * percentile));
+      int end = static_cast<int>(std::floor(distribution.size() * (1.0f - percentile)));
+
+      float a = 0;
+      float b = 0;
+
+      if (start < end &&
+        start >= 0 &&
+        end < static_cast<int>(distribution.size()))
+      {
+        a = distribution[start];
+        b = distribution[end];
+      }
+      else if (!distribution.empty())
+      {
+        // Too small distribution: Use full range
+        a = distribution.front();
+        b = distribution.back();
+      }
+
+      //printf("WINDOWING %f %f\n", a, b);
+
+      for (const auto& pair : doseCtWidgetLayerPairs_)
+      {
+        auto widget = pair.first;
+        auto layer = pair.second;
+        RenderStyle s = widget->GetLayerStyle(layer);
+        s.windowing_ = ImageWindowing_Custom;
+        s.customWindowCenter_ = static_cast<float>(converter_.Apply((a + b) / 2.0f));
+        s.customWindowWidth_ = static_cast<float>(converter_.Apply(b - a));
+
+        // 96.210556 => 192.421112
+        widget->SetLayerStyle(layer, s);
+        printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_);
+      }
+    }
+      
+
+
+      size_t AddDoseLayer(SliceViewerWidget& widget,
+        OrthancVolumeImage& volume, VolumeProjection projection);
+
+      void AddStructLayer(
+        SliceViewerWidget& widget, StructureSetLoader& loader);
+
+      SliceViewerWidget* CreateDoseCtWidget(
+        std::unique_ptr<OrthancVolumeImage>& ct,
+        std::unique_ptr<OrthancVolumeImage>& dose,
+        std::unique_ptr<StructureSetLoader>& structLoader,
+        VolumeProjection projection);
+
+      void AddCtLayer(SliceViewerWidget& widget, OrthancVolumeImage& volume);
+
+      std::unique_ptr<Interactor>         mainWidgetInteractor_;
+      const DicomSeriesVolumeSlicer*    source_;
+      unsigned int                      slice_;
+
+      std::string                                        ctSeries_;
+      std::string                                        doseInstance_;
+      std::string                                        doseSeries_;
+      std::string                                        structInstance_;
+      std::unique_ptr<OrthancStone::OrthancVolumeImage>    dose_;
+      std::unique_ptr<OrthancStone::OrthancVolumeImage>    ct_;
+      std::unique_ptr<OrthancStone::StructureSetLoader>    struct_;
+
+    public:
+      RtViewerDemoApplication(MessageBroker& broker) :
+        IObserver(broker),
+        source_(NULL),
+        slice_(0)
+      {
+      }
+
+      /*
+      dev options on bgo xps15
+
+      COMMAND LINE
+      --ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa --dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb --struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
+
+      URL PARAMETERS
+      ?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa&dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb&struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9
+
+      */
+
+      void ParseParameters(const boost::program_options::variables_map&  parameters)
+      {
+        // Generic
+        {
+          if (parameters.count("verbose"))
+          {
+            Orthanc::Logging::EnableInfoLevel(true);
+            LOG(INFO) << "Verbose logs (info) are enabled";
+          }
+        }
+
+        {
+          if (parameters.count("trace"))
+          {
+            LOG(INFO) << "parameters.count(\"trace\") != 0";
+            Orthanc::Logging::EnableTraceLevel(true);
+            VLOG(1) << "Trace logs (debug) are enabled";
+          }
+        }
+
+        // CT series
+        {
+
+          if (parameters.count("ct-series") != 1)
+          {
+            LOG(ERROR) << "There must be exactly one CT series specified";
+            throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+          }
+          ctSeries_ = parameters["ct-series"].as<std::string>();
+        }
+
+        // RTDOSE 
+        {
+          if (parameters.count("dose-instance") == 1)
+          {
+            doseInstance_ = parameters["dose-instance"].as<std::string>();
+          }
+          else
+          {
+#ifdef BGO_NOT_IMPLEMENTED_YET
+            // Dose series
+            if (parameters.count("dose-series") != 1)
+            {
+              LOG(ERROR) << "the RTDOSE series is missing";
+              throw Orthanc::OrthancException(
+                Orthanc::ErrorCode_ParameterOutOfRange);
+            }
+            doseSeries_ = parameters["ct"].as<std::string>();
+#endif
+            LOG(ERROR) << "the RTSTRUCT instance is missing";
+            throw Orthanc::OrthancException(
+              Orthanc::ErrorCode_ParameterOutOfRange);
+          }
+        }
+        
+        // RTSTRUCT 
+        {
+          if (parameters.count("struct-instance") == 1)
+          {
+            structInstance_ = parameters["struct-instance"].as<std::string>();
+          }
+          else
+          {
+#ifdef BGO_NOT_IMPLEMENTED_YET
+            // Struct series
+            if (parameters.count("struct-series") != 1)
+            {
+              LOG(ERROR) << "the RTSTRUCT series is missing";
+              throw Orthanc::OrthancException(
+                Orthanc::ErrorCode_ParameterOutOfRange);
+            }
+            structSeries_ = parameters["struct-series"].as<std::string>();
+#endif
+            LOG(ERROR) << "the RTSTRUCT instance is missing";
+            throw Orthanc::OrthancException(
+              Orthanc::ErrorCode_ParameterOutOfRange);
+          }
+        }
+      }
+
+      virtual void DeclareStartupOptions(
+        boost::program_options::options_description& options)
+      {
+        boost::program_options::options_description generic(
+          "RtViewerDemo options. Please note that some of these options "
+          "are mutually exclusive");
+        generic.add_options()
+          ("ct-series", boost::program_options::value<std::string>(),
+            "Orthanc ID of the CT series")
+          ("dose-instance", boost::program_options::value<std::string>(), 
+            "Orthanc ID of the RTDOSE instance (incompatible with dose-series)")
+          ("dose-series", boost::program_options::value<std::string>(), 
+            "NOT IMPLEMENTED YET. Orthanc ID of the RTDOSE series (incompatible"
+            " with dose-instance)")
+          ("struct-instance", boost::program_options::value<std::string>(), 
+            "Orthanc ID of the RTSTRUCT instance (incompatible with struct-"
+            "series)")
+          ("struct-series", boost::program_options::value<std::string>(), 
+            "NOT IMPLEMENTED YET. Orthanc ID of the RTSTRUCT (incompatible with"
+            " struct-instance)")
+          ("smooth", boost::program_options::value<bool>()->default_value(true),
+            "Enable bilinear image smoothing")
+          ;
+
+        options.add(generic);
+      }
+
+      virtual void Initialize(
+        StoneApplicationContext*                      context,
+        IStatusBar&                                   statusBar,
+        const boost::program_options::variables_map&  parameters)
+      {
+        using namespace OrthancStone;
+
+        ParseParameters(parameters);
+
+        context_ = context;
+
+        statusBar.SetMessage("Use the key \"s\" to reinitialize the layout");
+
+        if (!ctSeries_.empty())
+        {
+          printf("CT = [%s]\n", ctSeries_.c_str());
+
+          ct_.reset(new OrthancStone::OrthancVolumeImage(
+            IObserver::GetBroker(), context->GetOrthancApiClient(), false));
+          ct_->ScheduleLoadSeries(ctSeries_);
+          //ct_->ScheduleLoadSeries(
+          //  "a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa");
+          //ct_->ScheduleLoadSeries(
+          //  "03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0");
+        }
+
+        if (!doseSeries_.empty() ||
+          !doseInstance_.empty())
+        {
+          dose_.reset(new OrthancStone::OrthancVolumeImage(
+            IObserver::GetBroker(), context->GetOrthancApiClient(), true));
+
+
+          dose_->RegisterObserverCallback(
+            new Callable<RtViewerDemoApplication, ISlicedVolume::VolumeReadyMessage>
+            (*this, &RtViewerDemoApplication::OnVolumeReadyMessage));
+
+          dose_->RegisterObserverCallback(
+            new Callable<RtViewerDemoApplication, ISlicedVolume::SliceContentChangedMessage>
+            (*this, &RtViewerDemoApplication::OnSliceContentChangedMessage));
+
+          if (doseInstance_.empty())
+          {
+            dose_->ScheduleLoadSeries(doseSeries_);
+          }
+          else
+          {
+            dose_->ScheduleLoadInstance(doseInstance_);
+          }
+
+          //dose_->ScheduleLoadInstance(
+            //"830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb");  // 1
+          //dose_->ScheduleLoadInstance(
+            //"269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c"); //0522c0001 TCIA
+        }
+
+        if (!structInstance_.empty())
+        {
+          struct_.reset(new OrthancStone::StructureSetLoader(
+            IObserver::GetBroker(), context->GetOrthancApiClient()));
+
+          struct_->ScheduleLoadInstance(structInstance_);
+
+          //struct_->ScheduleLoadInstance(
+            //"54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9");
+          //struct_->ScheduleLoadInstance(
+            //"17cd032b-ad92a438-ca05f06a-f9e96668-7e3e9e20"); // 0522c0001 TCIA
+        }
+
+        mainWidget_ = new LayoutWidget("main-layout");
+        mainWidget_->SetBackgroundColor(0, 0, 0);
+        mainWidget_->SetBackgroundCleared(true);
+        mainWidget_->SetPadding(0);
+
+        auto axialWidget = CreateDoseCtWidget
+        (ct_, dose_, struct_, OrthancStone::VolumeProjection_Axial);
+        mainWidget_->AddWidget(axialWidget);
+               
+        std::unique_ptr<OrthancStone::LayoutWidget> subLayout(
+          new OrthancStone::LayoutWidget("main-layout"));
+        subLayout->SetVertical();
+        subLayout->SetPadding(5);
+
+        auto coronalWidget = CreateDoseCtWidget
+        (ct_, dose_, struct_, OrthancStone::VolumeProjection_Coronal);
+        subLayout->AddWidget(coronalWidget);
+
+        auto sagittalWidget = CreateDoseCtWidget
+        (ct_, dose_, struct_, OrthancStone::VolumeProjection_Sagittal);
+        subLayout->AddWidget(sagittalWidget);
+        
+        mainWidget_->AddWidget(subLayout.release());
+      }
+    };
+
+
+    size_t RtViewerDemoApplication::AddDoseLayer(
+      SliceViewerWidget& widget,
+      OrthancVolumeImage& volume, VolumeProjection projection)
+    {
+      size_t layer = widget.AddLayer(
+        new VolumeImageMPRSlicer(IObserver::GetBroker(), volume));
+
+      RenderStyle s;
+      //s.drawGrid_ = true;
+      s.SetColor(255, 0, 0);  // Draw missing PET layer in red
+      s.alpha_ = 0.3f;
+      s.applyLut_ = true;
+      s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET;
+      s.interpolation_ = ImageInterpolation_Bilinear;
+      widget.SetLayerStyle(layer, s);
+
+      return layer;
+    }
+
+    void RtViewerDemoApplication::AddStructLayer(
+      SliceViewerWidget& widget, StructureSetLoader& loader)
+    {
+      widget.AddLayer(new DicomStructureSetSlicer(
+        IObserver::GetBroker(), loader));
+    }
+
+    SliceViewerWidget* RtViewerDemoApplication::CreateDoseCtWidget(
+      std::unique_ptr<OrthancVolumeImage>& ct,
+      std::unique_ptr<OrthancVolumeImage>& dose,
+      std::unique_ptr<StructureSetLoader>& structLoader,
+      VolumeProjection projection)
+    {
+      std::unique_ptr<OrthancStone::SliceViewerWidget> widget(
+        new OrthancStone::SliceViewerWidget(IObserver::GetBroker(),
+          "ct-dose-widget"));
+
+      if (ct.get() != NULL)
+      {
+        AddCtLayer(*widget, *ct);
+      }
+
+      if (dose.get() != NULL)
+      {
+        size_t layer = AddDoseLayer(*widget, *dose, projection);
+
+        // we need to store the dose rendering widget because we'll update them
+        // according to various asynchronous events
+        doseCtWidgetLayerPairs_.push_back(std::make_pair(widget.get(), layer));
+#if 0
+        interactors_.push_back(new VolumeImageInteractor(
+          IObserver::GetBroker(), *dose, *widget, projection));
+#else
+        interactors_.push_back(new DoseInteractor(
+          IObserver::GetBroker(), *dose, *widget, projection, layer));
+#endif
+      }
+      else if (ct.get() != NULL)
+      {
+        interactors_.push_back(
+          new VolumeImageInteractor(
+            IObserver::GetBroker(), *ct, *widget, projection));
+      }
+
+      if (structLoader.get() != NULL)
+      {
+        AddStructLayer(*widget, *structLoader);
+      }
+
+      return widget.release();
+    }
+
+    void RtViewerDemoApplication::AddCtLayer(
+      SliceViewerWidget& widget,
+      OrthancVolumeImage& volume)
+    {
+      size_t layer = widget.AddLayer(
+        new VolumeImageMPRSlicer(IObserver::GetBroker(), volume));
+
+      RenderStyle s;
+      //s.drawGrid_ = true;
+      s.alpha_ = 1;
+      s.windowing_ = ImageWindowing_Bone;
+      widget.SetLayerStyle(layer, s);
+    }
+  }
+}
+
+
+
+#if ORTHANC_ENABLE_WASM==1
+
+#include "Platforms/Wasm/WasmWebService.h"
+#include "Platforms/Wasm/WasmViewport.h"
+
+#include <emscripten/emscripten.h>
+
+//#include "SampleList.h"
+
+
+OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker)
+{
+  return new OrthancStone::Samples::RtViewerDemoApplication(broker);
+}
+
+OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, OrthancStone::IStoneApplication* application)
+{
+  return dynamic_cast<OrthancStone::Samples::RtViewerDemoApplication*>(application)->CreateWasmApplicationAdapter(broker);
+}
+
+#else
+
+//#include "SampleList.h"
+#if ORTHANC_ENABLE_SDL==1
+#include "Applications/Sdl/SdlStoneApplicationRunner.h"
+#endif
+#if ORTHANC_ENABLE_QT==1
+#include "Applications/Qt/SampleQtApplicationRunner.h"
+#endif
+#include "Framework/Messages/MessageBroker.h"
+
+int main(int argc, char* argv[])
+{
+  OrthancStone::MessageBroker broker;
+  OrthancStone::Samples::RtViewerDemoApplication sampleStoneApplication(broker);
+
+#if ORTHANC_ENABLE_SDL==1
+  OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(broker, sampleStoneApplication);
+  return sdlApplicationRunner.Execute(argc, argv);
+#endif
+#if ORTHANC_ENABLE_QT==1
+  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(broker, sampleStoneApplication);
+  return qtAppRunner.Execute(argc, argv);
+#endif
+}
+
+
+#endif
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/nginx.local.conf	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,44 @@
+# Local config to serve the WASM samples static files and reverse proxy Orthanc.
+# Uses port 9977 instead of 80.
+
+# `events` section is mandatory
+events {
+  worker_connections 1024; # Default: 1024
+}
+
+http {
+
+  # prevent nginx sync issues on OSX
+  proxy_buffering off;
+
+  server {
+    listen 9977 default_server;
+    client_max_body_size 4G;
+
+    # location may have to be adjusted depending on your OS and nginx install
+    include /etc/nginx/mime.types;
+    # if not in your system mime.types, add this line to support WASM:
+    # types {
+    #    application/wasm                      wasm; 
+    # }
+
+    # serve WASM static files
+    root build-web/;
+    location / {
+	}
+
+    # reverse proxy orthanc
+	location /orthanc/ {
+		rewrite /orthanc(.*) $1 break;
+		proxy_pass http://127.0.0.1:8042;
+		proxy_set_header Host $http_host;
+		proxy_set_header my-auth-header good-token;
+		proxy_request_buffering off;
+		proxy_max_temp_file_size 0;
+		client_max_body_size 0;
+	}
+
+
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.html	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,25 @@
+<!doctype html>
+
+<html lang="us">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+    <!-- Disable pinch zoom on mobile devices -->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="HandheldFriendly" content="true" />
+
+    <title>Simple Viewer</title>
+    <link href="samples-styles.css" rel="stylesheet" />
+
+<body>
+  <div style="width: 100%; height: 5%">
+    <p>RTSTRUCT viewer demonstration</p>
+  </div>
+  <div style="width: 100%; height: 95%">
+    <canvas id="canvas"></canvas>
+  </div>
+  <script type="text/javascript" src="app-rt-viewer-demo.js"></script>
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.ts	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,5 @@
+import { InitializeWasmApplication } from '../../../Platforms/Wasm/wasm-application-runner';
+
+
+InitializeWasmApplication("RtViewerDemo", "/orthanc");
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/rt-viewer-demo.tsconfig.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,8 @@
+{
+    "extends" : "./tsconfig-samples",
+    "compilerOptions": {
+    },
+    "include" : [
+        "rt-viewer-demo.ts"
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/samples-styles.css	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,16 @@
+html, body {
+  width: 100%;
+  height: 100%;
+  margin: 0px;
+  border: 0;
+  overflow: hidden; /*  Disable scrollbars */
+  display: block;  /* No floating content on sides */
+  background-color: black;
+  color: white;
+  font-family: Arial, Helvetica, sans-serif;
+}
+
+canvas {
+  left:0px;
+  top:0px;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/start-serving-files.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+sudo nginx -p $(pwd) -c nginx.local.conf
+
+echo "Please browse to :"
+
+echo "http://localhost:9977/rt-viewer-demo.html?ct-series=a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa&dose-instance=830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb&struct-instance=54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"
+
+echo "(This requires you have uploaded the correct files to your local Orthanc instance)"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/stop-serving-files.sh	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+sudo nginx -s stop
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/rt-viewer-demo/tsconfig-samples.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,11 @@
+{
+    "extends" : "../../../Platforms/Wasm/tsconfig-stone.json",
+    "compilerOptions": {
+        "sourceMap": false,
+        "lib" : [
+            "es2017",
+            "dom",
+            "dom.iterable"
+        ]
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Samples/Deprecated/tsconfig-stone.json	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,7 @@
+{
+    "include" : [
+        "../../Platforms/Wasm/stone-framework-loader.ts",
+        "../../Platforms/Wasm/wasm-application-runner.ts",
+        "../../Platforms/Wasm/wasm-viewport.ts"
+    ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlCairoSurface.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,94 @@
+/**
+ * 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 "SdlCairoSurface.h"
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  SdlCairoSurface::SdlCairoSurface(SdlWindow& window) :
+    window_(window),
+    sdlSurface_(NULL)
+  {
+  }
+
+
+  SdlCairoSurface::~SdlCairoSurface()
+  {
+    if (sdlSurface_)
+    {
+      SDL_FreeSurface(sdlSurface_);
+    }
+  }
+
+
+  void SdlCairoSurface::SetSize(unsigned int width,
+                                unsigned int height)
+  {
+    if (cairoSurface_.get() == NULL ||
+        cairoSurface_->GetWidth() != width ||
+        cairoSurface_->GetHeight() != height)
+    {
+      cairoSurface_.reset(new CairoSurface(width, height, false /* no alpha */));
+
+      // TODO Big endian?
+      static const uint32_t rmask = 0x00ff0000;
+      static const uint32_t gmask = 0x0000ff00;
+      static const uint32_t bmask = 0x000000ff;
+
+      if (sdlSurface_)
+      {
+        SDL_FreeSurface(sdlSurface_);
+      }
+
+      sdlSurface_ = SDL_CreateRGBSurfaceFrom(cairoSurface_->GetBuffer(), width, height, 32,
+                                             cairoSurface_->GetPitch(), rmask, gmask, bmask, 0);
+      if (!sdlSurface_)
+      {
+        LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface";
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+  }
+
+
+  void SdlCairoSurface::Render(Deprecated::IViewport& viewport)
+  {
+    if (cairoSurface_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    Orthanc::ImageAccessor target;
+    cairoSurface_->GetWriteableAccessor(target);
+
+    if (viewport.Render(target))
+    {
+      window_.Render(sdlSurface_);
+    }
+  }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlCairoSurface.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,56 @@
+/**
+ * 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
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include "../../Framework/Viewport/SdlWindow.h"
+#include "../../Framework/Wrappers/CairoSurface.h"
+#include "../../Framework/Deprecated/Viewport/IViewport.h"
+
+#include <Core/Compatibility.h>
+
+#include <SDL_render.h>
+#include <boost/thread/mutex.hpp>
+
+namespace OrthancStone
+{
+  class SdlCairoSurface : public boost::noncopyable
+  {
+  private:
+    std::unique_ptr<CairoSurface>  cairoSurface_;
+    SdlWindow&                   window_;
+    SDL_Surface*                 sdlSurface_;
+
+  public:
+    SdlCairoSurface(SdlWindow& window);
+
+    ~SdlCairoSurface();
+
+    void SetSize(unsigned int width,
+                 unsigned int height);
+
+    void Render(Deprecated::IViewport& viewport);
+  };
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlEngine.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,282 @@
+/**
+ * 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 "SdlEngine.h"
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include <Core/Logging.h>
+
+#include <SDL.h>
+
+namespace OrthancStone
+{
+  void SdlEngine::SetSize(unsigned int width,
+                          unsigned int height)
+  {
+    NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
+    locker.GetCentralViewport().SetSize(width, height);
+    surface_.SetSize(width, height);
+  }
+
+
+  void SdlEngine::RenderFrame()
+  {
+    if (viewportChanged_)
+    {
+      NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
+      surface_.Render(locker.GetCentralViewport());
+
+      viewportChanged_ = false;
+    }
+  }
+
+
+  KeyboardModifiers SdlEngine::GetKeyboardModifiers(const uint8_t* keyboardState,
+                                                    const int scancodeCount)
+  {
+    int result = KeyboardModifiers_None;
+
+    if (keyboardState != NULL)
+    {
+      if (SDL_SCANCODE_LSHIFT < scancodeCount &&
+          keyboardState[SDL_SCANCODE_LSHIFT])
+      {
+        result |= KeyboardModifiers_Shift;
+      }
+
+      if (SDL_SCANCODE_RSHIFT < scancodeCount &&
+          keyboardState[SDL_SCANCODE_RSHIFT])
+      {
+        result |= KeyboardModifiers_Shift;
+      }
+
+      if (SDL_SCANCODE_LCTRL < scancodeCount &&
+          keyboardState[SDL_SCANCODE_LCTRL])
+      {
+        result |= KeyboardModifiers_Control;
+      }
+
+      if (SDL_SCANCODE_RCTRL < scancodeCount &&
+          keyboardState[SDL_SCANCODE_RCTRL])
+      {
+        result |= KeyboardModifiers_Control;
+      }
+
+      if (SDL_SCANCODE_LALT < scancodeCount &&
+          keyboardState[SDL_SCANCODE_LALT])
+      {
+        result |= KeyboardModifiers_Alt;
+      }
+
+      if (SDL_SCANCODE_RALT < scancodeCount &&
+          keyboardState[SDL_SCANCODE_RALT])
+      {
+        result |= KeyboardModifiers_Alt;
+      }
+    }
+
+    return static_cast<KeyboardModifiers>(result);
+  }
+
+
+  SdlEngine::SdlEngine(SdlWindow& window,
+                       NativeStoneApplicationContext& context) :
+    window_(window),
+    context_(context),
+    surface_(window),
+    viewportChanged_(true)
+  {
+  }
+  
+
+  void SdlEngine::Run()
+  {
+    int scancodeCount = 0;
+    const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
+
+    SetSize(window_.GetWidth(), window_.GetHeight());
+    
+    {
+      NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
+      locker.GetCentralViewport().FitContent();
+    }
+    
+    bool stop = false;
+    while (!stop)
+    {
+      RenderFrame();
+
+      SDL_Event event;
+
+      while (!stop &&
+             SDL_PollEvent(&event))
+      {
+        NativeStoneApplicationContext::GlobalMutexLocker locker(context_);
+
+        if (event.type == SDL_QUIT)
+        {
+          stop = true;
+          break;
+        }
+        else if (event.type == SDL_MOUSEBUTTONDOWN)
+        {
+          KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
+
+          switch (event.button.button)
+          {
+          case SDL_BUTTON_LEFT:
+            locker.GetCentralViewport().MouseDown(MouseButton_Left, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
+            break;
+            
+          case SDL_BUTTON_RIGHT:
+            locker.GetCentralViewport().MouseDown(MouseButton_Right, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
+            break;
+            
+          case SDL_BUTTON_MIDDLE:
+            locker.GetCentralViewport().MouseDown(MouseButton_Middle, event.button.x, event.button.y, modifiers, std::vector<Deprecated::Touch>());
+            break;
+
+          default:
+            break;
+          }
+        }
+        else if (event.type == SDL_MOUSEMOTION)
+        {
+          locker.GetCentralViewport().MouseMove(event.button.x, event.button.y, std::vector<Deprecated::Touch>());
+        }
+        else if (event.type == SDL_MOUSEBUTTONUP)
+        {
+          locker.GetCentralViewport().MouseUp();
+        }
+        else if (event.type == SDL_WINDOWEVENT)
+        {
+          switch (event.window.event)
+          {
+          case SDL_WINDOWEVENT_LEAVE:
+            locker.GetCentralViewport().MouseLeave();
+            break;
+
+          case SDL_WINDOWEVENT_ENTER:
+            locker.GetCentralViewport().MouseEnter();
+            break;
+
+          case SDL_WINDOWEVENT_SIZE_CHANGED:
+            SetSize(event.window.data1, event.window.data2);
+            break;
+
+          default:
+            break;
+          }
+        }
+        else if (event.type == SDL_MOUSEWHEEL)
+        {
+          KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
+
+          int x, y;
+          SDL_GetMouseState(&x, &y);
+
+          if (event.wheel.y > 0)
+          {
+            locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Up, x, y, modifiers);
+          }
+          else if (event.wheel.y < 0)
+          {
+            locker.GetCentralViewport().MouseWheel(MouseWheelDirection_Down, x, y, modifiers);
+          }
+        }
+        else if (event.type == SDL_KEYDOWN &&
+                 event.key.repeat == 0 /* Ignore key bounce */)
+        {
+          KeyboardModifiers modifiers = GetKeyboardModifiers(keyboardState, scancodeCount);
+
+          switch (event.key.keysym.sym)
+          {
+          case SDLK_a:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'a', modifiers);  break;
+          case SDLK_b:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'b', modifiers);  break;
+          case SDLK_c:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'c', modifiers);  break;
+          case SDLK_d:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'd', modifiers);  break;
+          case SDLK_e:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'e', modifiers);  break;
+          case SDLK_f:    window_.ToggleMaximize();                         break;
+          case SDLK_g:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'g', modifiers);  break;
+          case SDLK_h:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'h', modifiers);  break;
+          case SDLK_i:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'i', modifiers);  break;
+          case SDLK_j:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'j', modifiers);  break;
+          case SDLK_k:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'k', modifiers);  break;
+          case SDLK_l:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'l', modifiers);  break;
+          case SDLK_m:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'm', modifiers);  break;
+          case SDLK_n:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'n', modifiers);  break;
+          case SDLK_o:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'o', modifiers);  break;
+          case SDLK_p:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'p', modifiers);  break;
+          case SDLK_q:    stop = true;                                      break;
+          case SDLK_r:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'r', modifiers);  break;
+          case SDLK_s:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 's', modifiers);  break;
+          case SDLK_t:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 't', modifiers);  break;
+          case SDLK_u:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'u', modifiers);  break;
+          case SDLK_v:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'v', modifiers);  break;
+          case SDLK_w:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'w', modifiers);  break;
+          case SDLK_x:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'x', modifiers);  break;
+          case SDLK_y:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'y', modifiers);  break;
+          case SDLK_z:    locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, 'z', modifiers);  break;
+          case SDLK_KP_0: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '0', modifiers);  break;
+          case SDLK_KP_1: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '1', modifiers);  break;
+          case SDLK_KP_2: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '2', modifiers);  break;
+          case SDLK_KP_3: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '3', modifiers);  break;
+          case SDLK_KP_4: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '4', modifiers);  break;
+          case SDLK_KP_5: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '5', modifiers);  break;
+          case SDLK_KP_6: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '6', modifiers);  break;
+          case SDLK_KP_7: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '7', modifiers);  break;
+          case SDLK_KP_8: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '8', modifiers);  break;
+          case SDLK_KP_9: locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '9', modifiers);  break;
+
+          case SDLK_PLUS:
+          case SDLK_KP_PLUS:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '+', modifiers);  break;
+
+          case SDLK_MINUS:
+          case SDLK_KP_MINUS:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Generic, '-', modifiers);  break;
+
+          case SDLK_DELETE:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Delete, 0, modifiers);  break;
+          case SDLK_BACKSPACE:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Backspace, 0, modifiers);  break;
+          case SDLK_RIGHT:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Right, 0, modifiers);  break;
+          case SDLK_LEFT:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Left, 0, modifiers);  break;
+          case SDLK_UP:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Up, 0, modifiers);  break;
+          case SDLK_DOWN:
+            locker.GetCentralViewport().KeyPressed(KeyboardKeys_Down, 0, modifiers);  break;
+          default:
+            break;
+          }
+        }
+      }
+
+      // Small delay to avoid using 100% of CPU
+      SDL_Delay(1);
+    }
+  }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlEngine.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,61 @@
+/**
+ * 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
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include "../../Framework/Messages/ObserverBase.h"
+#include "../Generic/NativeStoneApplicationContext.h"
+#include "SdlCairoSurface.h"
+
+namespace OrthancStone
+{
+  class SdlEngine : public ObserverBase<SdlEngine>
+  {
+  private:
+    SdlWindow&                window_;
+    NativeStoneApplicationContext&  context_;
+    SdlCairoSurface           surface_;
+    bool                      viewportChanged_;
+
+    void SetSize(unsigned int width,
+                 unsigned int height);
+    
+    void RenderFrame();
+
+    static KeyboardModifiers GetKeyboardModifiers(const uint8_t* keyboardState,
+                                                  const int scancodeCount);
+
+  public:
+    SdlEngine(SdlWindow& window,
+              NativeStoneApplicationContext& context);
+  
+    void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
+    {
+      viewportChanged_ = true;
+    }
+
+    void Run();
+  };
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlOrthancSurface.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,108 @@
+/**
+ * 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 "SdlOrthancSurface.h"
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <Core/Images/Image.h>
+
+#include <SDL_render.h>
+
+namespace OrthancStone
+{
+  SdlOrthancSurface::SdlOrthancSurface(SdlWindow& window) :
+    window_(window),
+    sdlSurface_(NULL)
+  {
+  }
+
+
+  SdlOrthancSurface::~SdlOrthancSurface()
+  {
+    if (sdlSurface_)
+    {
+      SDL_FreeSurface(sdlSurface_);
+    }
+  }
+
+
+  void SdlOrthancSurface::SetSize(unsigned int width,
+                                  unsigned int height)
+  {
+    if (image_.get() == NULL ||
+        image_->GetWidth() != width ||
+        image_->GetHeight() != height)
+    {
+      image_.reset(new Orthanc::Image(Orthanc::PixelFormat_BGRA32, width, height, true));  // (*)
+
+      if (image_->GetPitch() != image_->GetWidth() * 4)
+      {
+        // This should have been ensured by setting "forceMinimalPitch" to "true" (*)
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+
+      // TODO Big endian?
+      static const uint32_t rmask = 0x00ff0000;
+      static const uint32_t gmask = 0x0000ff00;
+      static const uint32_t bmask = 0x000000ff;
+
+      if (sdlSurface_)
+      {
+        SDL_FreeSurface(sdlSurface_);
+      }
+
+      sdlSurface_ = SDL_CreateRGBSurfaceFrom(image_->GetBuffer(), width, height, 32,
+                                             image_->GetPitch(), rmask, gmask, bmask, 0);
+      if (!sdlSurface_)
+      {
+        LOG(ERROR) << "Cannot create a SDL surface from a Orthanc surface";
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+  }
+
+
+  Orthanc::ImageAccessor& SdlOrthancSurface::GetImage()
+  {
+    if (image_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    return *image_;
+  }
+
+
+  void SdlOrthancSurface::Render()
+  {
+    if (image_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    window_.Render(sdlSurface_);
+  }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlOrthancSurface.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,56 @@
+/**
+ * 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
+
+#if ORTHANC_ENABLE_SDL == 1
+
+#include "../../Framework/Viewport/SdlWindow.h"
+
+#include <Core/Compatibility.h>
+#include <Core/Images/ImageAccessor.h>
+
+#include <boost/thread/mutex.hpp>
+
+namespace OrthancStone
+{
+  class SdlOrthancSurface : public boost::noncopyable
+  {
+  private:
+    std::unique_ptr<Orthanc::ImageAccessor>  image_;
+    SdlWindow&                             window_;
+    SDL_Surface*                           sdlSurface_;
+
+  public:
+    SdlOrthancSurface(SdlWindow& window);
+
+    ~SdlOrthancSurface();
+
+    void SetSize(unsigned int width,
+                 unsigned int height);
+
+    Orthanc::ImageAccessor& GetImage();
+
+    void Render();
+  };
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlStoneApplicationRunner.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,138 @@
+/**
+ * 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/>.
+ **/
+
+
+#if ORTHANC_ENABLE_SDL != 1
+#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
+#endif
+
+#include "SdlStoneApplicationRunner.h"
+
+#include "../../Platforms/Generic/OracleWebService.h"
+#include "SdlEngine.h"
+
+#include <Core/Logging.h>
+#include <Core/HttpClient.h>
+#include <Core/Toolbox.h>
+#include <Core/OrthancException.h>
+#include <Plugins/Samples/Common/OrthancHttpConnection.h>
+
+#include <boost/program_options.hpp>
+
+namespace OrthancStone
+{
+  void SdlStoneApplicationRunner::Initialize()
+  {
+    SdlWindow::GlobalInitialize();
+  }
+
+  
+  void SdlStoneApplicationRunner::DeclareCommandLineOptions(boost::program_options::options_description& options)
+  {
+    boost::program_options::options_description sdl("SDL options");
+    sdl.add_options()
+        ("width", boost::program_options::value<int>()->default_value(1024), "Initial width of the SDL window")
+        ("height", boost::program_options::value<int>()->default_value(768), "Initial height of the SDL window")
+        ("opengl", boost::program_options::value<bool>()->default_value(true), "Enable OpenGL in SDL")
+        ;
+
+    options.add(sdl);
+  }
+
+  
+  void SdlStoneApplicationRunner::ParseCommandLineOptions(const boost::program_options::variables_map& parameters)
+  {
+    if (!parameters.count("width") ||
+        !parameters.count("height") ||
+        !parameters.count("opengl"))
+    {
+      LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing";
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    int w = parameters["width"].as<int>();
+    int h = parameters["height"].as<int>();
+    if (w <= 0 || h <= 0)
+    {
+      LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive";
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    width_ = static_cast<unsigned int>(w);
+    height_ = static_cast<unsigned int>(h);
+    LOG(WARNING) << "Initial display size: " << width_ << "x" << height_;
+
+    enableOpenGl_ = parameters["opengl"].as<bool>();
+    if (enableOpenGl_)
+    {
+      LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes";
+    }
+    else
+    {
+      LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance";
+    }
+  }
+
+  
+  void SdlStoneApplicationRunner::Run(NativeStoneApplicationContext& context,
+                                      const std::string& title,
+                                      int argc,
+                                      char* argv[])
+  {
+    /**************************************************************
+     * Run the application inside a SDL window
+     **************************************************************/
+
+    LOG(WARNING) << "Starting the application";
+
+    SdlWindow window(title.c_str(), width_, height_, enableOpenGl_);
+    boost::shared_ptr<SdlEngine> sdl(new SdlEngine(window, context));
+
+    {
+      NativeStoneApplicationContext::GlobalMutexLocker locker(context);
+
+      sdl->Register<Deprecated::IViewport::ViewportChangedMessage>
+        (locker.GetCentralViewport(), &SdlEngine::OnViewportChanged);
+
+      //context.GetCentralViewport().Register(sdl);  // (*)
+    }
+
+    context.Start();
+    sdl->Run();
+
+    LOG(WARNING) << "Stopping the application";
+
+    // Don't move the "Stop()" command below out of the block,
+    // otherwise the application might crash, because the
+    // "SdlEngine" is an observer of the viewport (*) and the
+    // update thread started by "context.Start()" would call a
+    // destructed object (the "SdlEngine" is deleted with the
+    // lexical scope).
+
+    // TODO Is this still true with message broker?
+    context.Stop();
+  }
+
+  
+  void SdlStoneApplicationRunner::Finalize()
+  {
+    SdlWindow::GlobalFinalize();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Sdl/SdlStoneApplicationRunner.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,60 @@
+/**
+ * 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 "../Generic/NativeStoneApplicationRunner.h"
+
+#if ORTHANC_ENABLE_SDL != 1
+#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
+#endif
+
+#include <SDL.h>   // Necessary to avoid undefined reference to `SDL_main'
+
+namespace OrthancStone
+{
+  class SdlStoneApplicationRunner : public NativeStoneApplicationRunner
+  {
+  private:
+    unsigned int  width_;
+    unsigned int  height_;
+    bool          enableOpenGl_;
+    
+  public:
+    SdlStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application) :
+      NativeStoneApplicationRunner(application)
+    {
+    }
+
+    virtual void Initialize();
+    
+    virtual void DeclareCommandLineOptions(boost::program_options::options_description& options);
+    
+    virtual void Run(NativeStoneApplicationContext& context,
+                     const std::string& title,
+                     int argc,
+                     char* argv[]);
+    
+    virtual void ParseCommandLineOptions(const boost::program_options::variables_map& parameters);
+    
+    virtual void Finalize();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/StoneApplicationContext.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,86 @@
+/**
+ * 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 "StoneApplicationContext.h"
+
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  void StoneApplicationContext::InitializeOrthanc()
+  {
+    if (webService_ == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    orthanc_.reset(new Deprecated::OrthancApiClient(*webService_, orthancBaseUrl_));
+  }
+
+
+  boost::shared_ptr<Deprecated::IWebService> StoneApplicationContext::GetWebService()
+  {
+    if (webService_ == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    return webService_;
+  }
+
+  
+  boost::shared_ptr<Deprecated::OrthancApiClient> StoneApplicationContext::GetOrthancApiClient()
+  {
+    if (orthanc_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    return orthanc_;
+  }
+
+  
+  void StoneApplicationContext::SetWebService(boost::shared_ptr<Deprecated::IWebService> webService)
+  {
+    webService_ = webService;
+    InitializeOrthanc();
+  }
+
+
+  void StoneApplicationContext::SetOrthancBaseUrl(const std::string& baseUrl)
+  {
+    // Make sure the base url ends with "/"
+    if (baseUrl.empty() ||
+        baseUrl[baseUrl.size() - 1] != '/')
+    {
+      orthancBaseUrl_ = baseUrl + "/";
+    }
+    else
+    {
+      orthancBaseUrl_ = baseUrl;
+    }
+
+    if (webService_ != NULL)
+    {
+      InitializeOrthanc();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/StoneApplicationContext.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,97 @@
+/**
+ * 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/Deprecated/Toolbox/IWebService.h"
+#include "../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h"
+#include "../Framework/Deprecated/Toolbox/OrthancApiClient.h"
+#include "../Framework/Deprecated/Viewport/WidgetViewport.h"
+
+
+#ifdef _MSC_VER
+  #if _MSC_VER > 1910
+    #define orthanc_override override
+  #else
+    #define orthanc_override
+  #endif
+#elif defined __GNUC__
+  #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+/* Test for GCC > 3.2.0 */
+  #if GCC_VERSION > 40900
+    #define orthanc_override override
+  #else
+    #define orthanc_override
+  #endif
+#else
+    #define orthanc_override
+#endif
+
+#include <list>
+
+namespace OrthancStone
+{
+  // a StoneApplicationContext contains the services that a StoneApplication
+  // uses and that depends on the environment in which the Application executes.
+  // I.e, the StoneApplicationContext provides a WebService interface such that
+  // the StoneApplication can perform HTTP requests.  In a WASM environment,
+  // the WebService is provided by the browser while, in a native environment,
+  // the WebService is provided by the OracleWebService (a C++ Http client)
+
+  class StoneApplicationContext : public boost::noncopyable
+  {
+  private:
+    boost::shared_ptr<Deprecated::IWebService>     webService_;
+    Deprecated::IDelayedCallExecutor*  delayedCallExecutor_;   // TODO => shared_ptr ??
+    boost::shared_ptr<Deprecated::OrthancApiClient>  orthanc_;
+    std::string                      orthancBaseUrl_;
+
+    void InitializeOrthanc();
+
+  public:
+    StoneApplicationContext() :
+      delayedCallExecutor_(NULL)
+    {
+    }
+
+    virtual ~StoneApplicationContext()
+    {
+    }
+
+    boost::shared_ptr<Deprecated::IWebService> GetWebService();
+
+    boost::shared_ptr<Deprecated::OrthancApiClient> GetOrthancApiClient();
+
+    void SetWebService(boost::shared_ptr<Deprecated::IWebService> webService);
+
+    void SetOrthancBaseUrl(const std::string& baseUrl);
+
+    void SetDelayedCallExecutor(Deprecated::IDelayedCallExecutor& delayedCallExecutor)
+    {
+      delayedCallExecutor_ = &delayedCallExecutor;
+    }
+
+    Deprecated::IDelayedCallExecutor& GetDelayedCallExecutor()
+    {
+      return *delayedCallExecutor_;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Wasm/StartupParametersBuilder.cpp	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,71 @@
+#include "StartupParametersBuilder.h"
+#include <iostream>
+#include <cstdio>
+#include "emscripten/html5.h"
+
+namespace OrthancStone
+{
+  void StartupParametersBuilder::Clear()
+  {
+    startupParameters_.clear();
+  }
+
+  void StartupParametersBuilder::SetStartupParameter(
+    const char* name,
+    const char* value)
+  {
+    startupParameters_.push_back(std::make_tuple(name, value));
+  }
+
+  void StartupParametersBuilder::GetStartupParameters(
+    boost::program_options::variables_map& parameters,
+    const boost::program_options::options_description& options) 
+  {
+    std::vector<std::string> argvStrings(startupParameters_.size() + 1);
+    // argv mirrors pointers to the internal argvStrings buffers.
+    // ******************************************************
+    // THIS IS HIGHLY DANGEROUS SO BEWARE!!!!!!!!!!!!!!
+    // ******************************************************
+    std::vector<const char*> argv(startupParameters_.size() + 1);
+    
+    int argCounter = 0;
+    argvStrings[argCounter] = "dummy.exe";
+    argv[argCounter] = argvStrings[argCounter].c_str();
+    
+    argCounter++;
+    
+    std::string cmdLine = "";
+    for ( StartupParameters::const_iterator it = startupParameters_.begin(); 
+          it != startupParameters_.end(); 
+          it++)
+    {
+      std::stringstream argSs;
+
+      argSs << "--" << std::get<0>(*it);
+      if(std::get<1>(*it).length() > 0)
+        argSs << "=" << std::get<1>(*it);
+      
+      argvStrings[argCounter] = argSs.str();
+      cmdLine = cmdLine + " " + argvStrings[argCounter];
+      std::cout << cmdLine << std::endl;
+      argv[argCounter] = argvStrings[argCounter].c_str();
+      argCounter++;
+    }
+
+
+    std::cout << "simulated cmdLine = \"" << cmdLine.c_str() << "\"\n";
+
+    try
+    {
+      boost::program_options::store(
+        boost::program_options::command_line_parser(argCounter, argv.data()).
+          options(options).allow_unregistered().run(), parameters);
+      boost::program_options::notify(parameters);
+    }
+    catch (boost::program_options::error& e)
+    {
+      std::cerr << "Error while parsing the command-line arguments: " <<
+        e.what() << std::endl;    
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Deprecated/Applications/Wasm/StartupParametersBuilder.h	Wed Apr 29 20:44:31 2020 +0200
@@ -0,0 +1,54 @@
+/**
+ * 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/program_options.hpp>
+#include <tuple>
+
+#if ORTHANC_ENABLE_SDL == 1
+#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 0
+#endif
+
+namespace OrthancStone
+{
+  // This class is used to generate boost program options from a dico.
+  // In a Wasm context, startup options are passed as URI arguments that
+  // are then passed to this class as a dico.
+  // This class regenerates a fake command-line and parses it to produce
+  // the same output as if the app was started at command-line.
+  class StartupParametersBuilder
+  {
+    typedef std::list<std::tuple<std::string, std::string>> StartupParameters;
+    StartupParameters startupParameters_;
+
+  public:
+
+    void Clear();
+    // Please note that if a parameter is a flag-style one, the value that 
+    // is passed should be an empty string
+    void SetStartupParameter(const char* name, const char* value);
+    void GetStartupParameters(
+      boost::program_options::variables_map& parameters_, 
+      const boost::program_options::options_description& options);
+  };
+
+}