changeset 732:c35e98d22764

move Deprecated classes to a separate folder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 21 May 2019 14:27:35 +0200
parents 529189f399ec
children 717eabfa749a
files Applications/Generic/NativeStoneApplicationContext.h Applications/IStoneApplication.h Applications/Samples/CMakeLists.txt Applications/Samples/SampleApplicationBase.h Applications/Samples/SimpleViewer/MainWidgetInteractor.h Applications/Samples/SimpleViewer/SimpleViewerApplication.h Applications/Samples/SimpleViewer/ThumbnailInteractor.h Applications/Samples/SimpleViewerApplicationSingleFile.h Applications/Samples/SingleFrameApplication.h Applications/Sdl/SdlCairoSurface.h Applications/StoneApplicationContext.h Framework/Deprecated/Layers/CircleMeasureTracker.cpp Framework/Deprecated/Layers/CircleMeasureTracker.h Framework/Deprecated/Layers/ColorFrameRenderer.cpp Framework/Deprecated/Layers/ColorFrameRenderer.h Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp Framework/Deprecated/Layers/DicomStructureSetSlicer.h Framework/Deprecated/Layers/FrameRenderer.cpp Framework/Deprecated/Layers/FrameRenderer.h Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp Framework/Deprecated/Layers/GrayscaleFrameRenderer.h Framework/Deprecated/Layers/ILayerRenderer.h Framework/Deprecated/Layers/IVolumeSlicer.h Framework/Deprecated/Layers/LineLayerRenderer.cpp Framework/Deprecated/Layers/LineLayerRenderer.h Framework/Deprecated/Layers/LineMeasureTracker.cpp Framework/Deprecated/Layers/LineMeasureTracker.h Framework/Deprecated/Layers/RenderStyle.cpp Framework/Deprecated/Layers/RenderStyle.h Framework/Deprecated/Layers/SeriesFrameRendererFactory.cpp Framework/Deprecated/Layers/SeriesFrameRendererFactory.h Framework/Deprecated/Layers/SingleFrameRendererFactory.cpp Framework/Deprecated/Layers/SingleFrameRendererFactory.h Framework/Deprecated/Layers/SliceOutlineRenderer.cpp Framework/Deprecated/Layers/SliceOutlineRenderer.h Framework/Deprecated/SmartLoader.cpp Framework/Deprecated/SmartLoader.h Framework/Deprecated/Toolbox/BaseWebService.cpp Framework/Deprecated/Toolbox/BaseWebService.h Framework/Deprecated/Toolbox/DicomFrameConverter.cpp Framework/Deprecated/Toolbox/DicomFrameConverter.h Framework/Deprecated/Toolbox/DownloadStack.cpp Framework/Deprecated/Toolbox/DownloadStack.h Framework/Deprecated/Toolbox/IDelayedCallExecutor.h Framework/Deprecated/Toolbox/IWebService.cpp Framework/Deprecated/Toolbox/IWebService.h Framework/Deprecated/Toolbox/OrthancApiClient.cpp Framework/Deprecated/Toolbox/OrthancApiClient.h Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp Framework/Deprecated/Toolbox/OrthancSlicesLoader.h Framework/Deprecated/Toolbox/Slice.cpp Framework/Deprecated/Toolbox/Slice.h Framework/Deprecated/Toolbox/ViewportGeometry.cpp Framework/Deprecated/Toolbox/ViewportGeometry.h Framework/Deprecated/Viewport/IMouseTracker.h Framework/Deprecated/Viewport/IStatusBar.h Framework/Deprecated/Viewport/IViewport.h Framework/Deprecated/Viewport/WidgetViewport.cpp Framework/Deprecated/Viewport/WidgetViewport.h Framework/Deprecated/Volumes/ISlicedVolume.h Framework/Deprecated/Volumes/IVolumeLoader.h Framework/Deprecated/Volumes/StructureSetLoader.cpp Framework/Deprecated/Volumes/StructureSetLoader.h Framework/Deprecated/Widgets/CairoWidget.cpp Framework/Deprecated/Widgets/CairoWidget.h Framework/Deprecated/Widgets/EmptyWidget.cpp Framework/Deprecated/Widgets/EmptyWidget.h Framework/Deprecated/Widgets/IWidget.h Framework/Deprecated/Widgets/IWorldSceneInteractor.h Framework/Deprecated/Widgets/IWorldSceneMouseTracker.h Framework/Deprecated/Widgets/LayoutWidget.cpp Framework/Deprecated/Widgets/LayoutWidget.h Framework/Deprecated/Widgets/PanMouseTracker.cpp Framework/Deprecated/Widgets/PanMouseTracker.h Framework/Deprecated/Widgets/PanZoomMouseTracker.cpp Framework/Deprecated/Widgets/PanZoomMouseTracker.h Framework/Deprecated/Widgets/SliceViewerWidget.cpp Framework/Deprecated/Widgets/SliceViewerWidget.h Framework/Deprecated/Widgets/TestCairoWidget.cpp Framework/Deprecated/Widgets/TestCairoWidget.h Framework/Deprecated/Widgets/TestWorldSceneWidget.cpp Framework/Deprecated/Widgets/TestWorldSceneWidget.h Framework/Deprecated/Widgets/WidgetBase.cpp Framework/Deprecated/Widgets/WidgetBase.h Framework/Deprecated/Widgets/WorldSceneWidget.cpp Framework/Deprecated/Widgets/WorldSceneWidget.h Framework/Deprecated/Widgets/ZoomMouseTracker.cpp Framework/Deprecated/Widgets/ZoomMouseTracker.h Framework/Deprecated/dev.h Framework/Layers/CircleMeasureTracker.cpp Framework/Layers/CircleMeasureTracker.h Framework/Layers/ColorFrameRenderer.cpp Framework/Layers/ColorFrameRenderer.h Framework/Layers/DicomSeriesVolumeSlicer.cpp Framework/Layers/DicomSeriesVolumeSlicer.h Framework/Layers/DicomStructureSetSlicer.cpp Framework/Layers/DicomStructureSetSlicer.h Framework/Layers/FrameRenderer.cpp Framework/Layers/FrameRenderer.h Framework/Layers/GrayscaleFrameRenderer.cpp Framework/Layers/GrayscaleFrameRenderer.h Framework/Layers/ILayerRenderer.h Framework/Layers/IVolumeSlicer.h Framework/Layers/LineLayerRenderer.cpp Framework/Layers/LineLayerRenderer.h Framework/Layers/LineMeasureTracker.cpp Framework/Layers/LineMeasureTracker.h Framework/Layers/RenderStyle.cpp Framework/Layers/RenderStyle.h Framework/Layers/SeriesFrameRendererFactory.cpp Framework/Layers/SeriesFrameRendererFactory.h Framework/Layers/SingleFrameRendererFactory.cpp Framework/Layers/SingleFrameRendererFactory.h Framework/Layers/SliceOutlineRenderer.cpp Framework/Layers/SliceOutlineRenderer.h Framework/Radiography/RadiographyDicomLayer.cpp Framework/Radiography/RadiographyDicomLayer.h Framework/Radiography/RadiographyLayerCropTracker.h Framework/Radiography/RadiographyLayerMaskTracker.h Framework/Radiography/RadiographyLayerMoveTracker.h Framework/Radiography/RadiographyLayerResizeTracker.h Framework/Radiography/RadiographyLayerRotateTracker.h Framework/Radiography/RadiographyScene.cpp Framework/Radiography/RadiographyScene.h Framework/Radiography/RadiographySceneReader.cpp Framework/Radiography/RadiographySceneReader.h Framework/Radiography/RadiographyWidget.h Framework/Radiography/RadiographyWindowingTracker.h Framework/SmartLoader.cpp Framework/SmartLoader.h Framework/Toolbox/BaseWebService.cpp Framework/Toolbox/BaseWebService.h Framework/Toolbox/DicomFrameConverter.cpp Framework/Toolbox/DicomFrameConverter.h Framework/Toolbox/DownloadStack.cpp Framework/Toolbox/DownloadStack.h Framework/Toolbox/IDelayedCallExecutor.h Framework/Toolbox/IWebService.cpp Framework/Toolbox/IWebService.h Framework/Toolbox/OrthancApiClient.cpp Framework/Toolbox/OrthancApiClient.h Framework/Toolbox/OrthancSlicesLoader.cpp Framework/Toolbox/OrthancSlicesLoader.h Framework/Toolbox/Slice.cpp Framework/Toolbox/Slice.h Framework/Toolbox/ViewportGeometry.cpp Framework/Toolbox/ViewportGeometry.h Framework/Viewport/IMouseTracker.h Framework/Viewport/IStatusBar.h Framework/Viewport/IViewport.h Framework/Viewport/WidgetViewport.cpp Framework/Viewport/WidgetViewport.h Framework/Volumes/ISlicedVolume.h Framework/Volumes/IVolumeLoader.h Framework/Volumes/ImageBuffer3D.h Framework/Volumes/StructureSetLoader.cpp Framework/Volumes/StructureSetLoader.h Framework/Widgets/CairoWidget.cpp Framework/Widgets/CairoWidget.h Framework/Widgets/EmptyWidget.cpp Framework/Widgets/EmptyWidget.h Framework/Widgets/IWidget.h Framework/Widgets/IWorldSceneInteractor.h Framework/Widgets/IWorldSceneMouseTracker.h Framework/Widgets/LayoutWidget.cpp Framework/Widgets/LayoutWidget.h Framework/Widgets/PanMouseTracker.cpp Framework/Widgets/PanMouseTracker.h Framework/Widgets/PanZoomMouseTracker.cpp Framework/Widgets/PanZoomMouseTracker.h Framework/Widgets/SliceViewerWidget.cpp Framework/Widgets/SliceViewerWidget.h Framework/Widgets/TestCairoWidget.cpp Framework/Widgets/TestCairoWidget.h Framework/Widgets/TestWorldSceneWidget.cpp Framework/Widgets/TestWorldSceneWidget.h Framework/Widgets/WidgetBase.cpp Framework/Widgets/WidgetBase.h Framework/Widgets/WorldSceneWidget.cpp Framework/Widgets/WorldSceneWidget.h Framework/Widgets/ZoomMouseTracker.cpp Framework/Widgets/ZoomMouseTracker.h Framework/dev.h Platforms/Generic/DelayedCallCommand.h Platforms/Generic/OracleDelayedCallExecutor.h Platforms/Generic/OracleWebService.cpp Platforms/Generic/OracleWebService.h Platforms/Generic/WebServiceCommandBase.h Platforms/Wasm/Defaults.cpp Platforms/Wasm/Defaults.h Platforms/Wasm/WasmDelayedCallExecutor.h Platforms/Wasm/WasmViewport.h Platforms/Wasm/WasmWebService.h Resources/CMake/OrthancStoneConfiguration.cmake Samples/WebAssembly/BasicScene.cpp UnitTestsSources/UnitTestsMain.cpp
diffstat 198 files changed, 11947 insertions(+), 12037 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Generic/NativeStoneApplicationContext.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationContext.h	Tue May 21 14:27:35 2019 +0200
@@ -21,9 +21,9 @@
 
 #pragma once
 
-#include "../../Framework/Viewport/WidgetViewport.h"
-#include "../../Framework/Volumes/ISlicedVolume.h"
-#include "../../Framework/Volumes/IVolumeLoader.h"
+#include "../../Framework/Deprecated/Viewport/WidgetViewport.h"
+#include "../../Framework/Deprecated/Volumes/ISlicedVolume.h"
+#include "../../Framework/Deprecated/Volumes/IVolumeLoader.h"
 
 #include <list>
 #include <boost/thread.hpp>
--- a/Applications/IStoneApplication.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/IStoneApplication.h	Tue May 21 14:27:35 2019 +0200
@@ -22,9 +22,10 @@
 #pragma once
 
 #include "StoneApplicationContext.h"
+#include "../Framework/Deprecated/Viewport/WidgetViewport.h"
+
 #include <boost/program_options.hpp>
-#include "../Framework/Viewport/WidgetViewport.h"
-#include "json/json.h"
+#include <json/json.h>
 
 namespace OrthancStone
 {
--- a/Applications/Samples/CMakeLists.txt	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/CMakeLists.txt	Tue May 21 14:27:35 2019 +0200
@@ -208,7 +208,6 @@
       ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/AppStatus.h
       ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp
       ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.h
-      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Messages.h
       ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp
       ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.h
       ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp
--- a/Applications/Samples/SampleApplicationBase.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/SampleApplicationBase.h	Tue May 21 14:27:35 2019 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../../Applications/IStoneApplication.h"
-#include "../../Framework/Widgets/WorldSceneWidget.h"
+#include "../../Framework/Deprecated/Widgets/WorldSceneWidget.h"
 
 #if ORTHANC_ENABLE_WASM==1
 #include "../../Platforms/Wasm/WasmPlatformApplicationAdapter.h"
--- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.h	Tue May 21 14:27:35 2019 +0200
@@ -20,7 +20,7 @@
 
 #pragma once
 
-#include "Framework/Widgets/IWorldSceneInteractor.h"
+#include "../../../Framework/Deprecated/Widgets/IWorldSceneInteractor.h"
 
 using namespace OrthancStone;
 
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Tue May 21 14:27:35 2019 +0200
@@ -29,12 +29,12 @@
 
 #include "Applications/IStoneApplication.h"
 
-#include "Framework/Layers/CircleMeasureTracker.h"
-#include "Framework/Layers/LineMeasureTracker.h"
-#include "Framework/Widgets/SliceViewerWidget.h"
-#include "Framework/Widgets/LayoutWidget.h"
-#include "Framework/Messages/IObserver.h"
-#include "Framework/SmartLoader.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"
--- a/Applications/Samples/SimpleViewer/ThumbnailInteractor.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/SimpleViewer/ThumbnailInteractor.h	Tue May 21 14:27:35 2019 +0200
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "Framework/Widgets/IWorldSceneInteractor.h"
+#include "../../../Framework/Deprecated/Widgets/IWorldSceneInteractor.h"
 
 using namespace OrthancStone;
 
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Tue May 21 14:27:35 2019 +0200
@@ -23,12 +23,12 @@
 
 #include "SampleApplicationBase.h"
 
-#include "../../Framework/Layers/CircleMeasureTracker.h"
-#include "../../Framework/Layers/LineMeasureTracker.h"
-#include "../../Framework/Widgets/SliceViewerWidget.h"
-#include "../../Framework/Widgets/LayoutWidget.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"
-#include "../../Framework/SmartLoader.h"
 
 #if ORTHANC_ENABLE_WASM==1
 #include "../../Platforms/Wasm/WasmPlatformApplicationAdapter.h"
--- a/Applications/Samples/SingleFrameApplication.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Samples/SingleFrameApplication.h	Tue May 21 14:27:35 2019 +0200
@@ -23,8 +23,8 @@
 
 #include "SampleApplicationBase.h"
 
-#include "../../Framework/Layers/DicomSeriesVolumeSlicer.h"
-#include "../../Framework/Widgets/SliceViewerWidget.h"
+#include "../../Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h"
+#include "../../Framework/Deprecated/Widgets/SliceViewerWidget.h"
 
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
--- a/Applications/Sdl/SdlCairoSurface.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/Sdl/SdlCairoSurface.h	Tue May 21 14:27:35 2019 +0200
@@ -25,7 +25,7 @@
 
 #include "SdlWindow.h"
 #include "../../Framework/Viewport/CairoSurface.h"
-#include "../../Framework/Viewport/IViewport.h"
+#include "../../Framework/Deprecated/Viewport/IViewport.h"
 
 #include <boost/thread/mutex.hpp>
 
--- a/Applications/StoneApplicationContext.h	Tue May 21 13:27:54 2019 +0200
+++ b/Applications/StoneApplicationContext.h	Tue May 21 14:27:35 2019 +0200
@@ -21,10 +21,10 @@
 
 #pragma once
 
-#include "../Framework/Toolbox/IWebService.h"
-#include "../Framework/Toolbox/IDelayedCallExecutor.h"
-#include "../Framework/Toolbox/OrthancApiClient.h"
-#include "../Framework/Viewport/WidgetViewport.h"
+#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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/CircleMeasureTracker.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,106 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "CircleMeasureTracker.h"
+
+#include <stdio.h>
+#include <boost/math/constants/constants.hpp>
+
+namespace Deprecated
+{
+  CircleMeasureTracker::CircleMeasureTracker(IStatusBar* statusBar,
+                                             const OrthancStone::CoordinateSystem3D& slice,
+                                             double x, 
+                                             double y,
+                                             uint8_t red,
+                                             uint8_t green,
+                                             uint8_t blue,
+                                             const Orthanc::Font& font) :
+    statusBar_(statusBar),
+    slice_(slice),
+    x1_(x),
+    y1_(y),
+    x2_(x),
+    y2_(y),
+    font_(font)
+  {
+    color_[0] = red;
+    color_[1] = green;
+    color_[2] = blue;
+  }
+    
+
+  void CircleMeasureTracker::Render(OrthancStone::CairoContext& context,
+                                    double zoom)
+  {
+    double x = (x1_ + x2_) / 2.0;
+    double y = (y1_ + y2_) / 2.0;
+
+    OrthancStone::Vector tmp;
+    OrthancStone::LinearAlgebra::AssignVector(tmp, x2_ - x1_, y2_ - y1_);
+    double r = boost::numeric::ublas::norm_2(tmp) / 2.0;
+
+    context.SetSourceColor(color_[0], color_[1], color_[2]);
+
+    cairo_t* cr = context.GetObject();
+    cairo_save(cr);
+    cairo_set_line_width(cr, 2.0 / zoom);
+    cairo_translate(cr, x, y);
+    cairo_arc(cr, 0, 0, r, 0, 2.0 * boost::math::constants::pi<double>());
+    cairo_stroke_preserve(cr);
+    cairo_stroke(cr);
+    cairo_restore(cr);
+
+    context.DrawText(font_, FormatRadius(), x, y, OrthancStone::BitmapAnchor_Center);
+  }
+    
+
+  double CircleMeasureTracker::GetRadius() const  // In millimeters
+  {
+    OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
+    OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
+    return boost::numeric::ublas::norm_2(b - a) / 2.0;
+  }
+
+
+  std::string CircleMeasureTracker::FormatRadius() const
+  {
+    char buf[64];
+    sprintf(buf, "%0.01f cm", GetRadius() / 10.0);
+    return buf;
+  }
+
+  void CircleMeasureTracker::MouseMove(int displayX,
+                                       int displayY,
+                                       double x,
+                                       double y,
+                                       const std::vector<Touch>& displayTouches,
+                                       const std::vector<Touch>& sceneTouches)
+  {
+    x2_ = x;
+    y2_ = y;
+
+    if (statusBar_ != NULL)
+    {
+      statusBar_->SetMessage("Circle radius: " + FormatRadius());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/CircleMeasureTracker.h	Tue May 21 14:27:35 2019 +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-2019 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 "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Viewport/IStatusBar.h"
+#include "../../Toolbox/CoordinateSystem3D.h"
+
+#include <Core/Images/Font.h>
+
+namespace Deprecated
+{
+  class CircleMeasureTracker : public IWorldSceneMouseTracker
+  {
+  private:
+    IStatusBar*           statusBar_;
+    OrthancStone::CoordinateSystem3D    slice_;
+    double                x1_;
+    double                y1_;
+    double                x2_;
+    double                y2_;
+    uint8_t               color_[3];
+    const Orthanc::Font&  font_;
+
+  public:
+    CircleMeasureTracker(IStatusBar* statusBar,
+                         const OrthancStone::CoordinateSystem3D& slice,
+                         double x, 
+                         double y,
+                         uint8_t red,
+                         uint8_t green,
+                         uint8_t blue,
+                         const Orthanc::Font& font);
+    
+    virtual bool HasRender() const
+    {
+      return true;
+    }
+
+    virtual void Render(OrthancStone::CairoContext& context,
+                        double zoom);
+    
+    double GetRadius() const;  // In millimeters
+
+    std::string FormatRadius() const;
+
+    virtual void MouseUp()
+    {
+      // Possibly create a new landmark "volume" with the circle in subclasses
+    }
+
+    virtual void MouseMove(int displayX,
+                           int displayY,
+                           double x,
+                           double y,
+                           const std::vector<Touch>& displayTouches,
+                           const std::vector<Touch>& sceneTouches);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/ColorFrameRenderer.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,62 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ColorFrameRenderer.h"
+
+#include <Core/OrthancException.h>
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
+
+namespace Deprecated
+{
+  OrthancStone::CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style)
+  {
+    std::auto_ptr<OrthancStone::CairoSurface> display
+      (new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
+
+    Orthanc::ImageAccessor target;
+    display->GetWriteableAccessor(target);
+    
+    Orthanc::ImageProcessing::Convert(target, *frame_);
+
+    return display.release();
+  }
+
+
+  ColorFrameRenderer::ColorFrameRenderer(const Orthanc::ImageAccessor& frame,
+                                         const OrthancStone::CoordinateSystem3D& framePlane,
+                                         double pixelSpacingX,
+                                         double pixelSpacingY,
+                                         bool isFullQuality) :
+    FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality),
+    frame_(Orthanc::Image::Clone(frame))
+  {
+    if (frame_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    if (frame_->GetFormat() != Orthanc::PixelFormat_RGB24)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/ColorFrameRenderer.h	Tue May 21 14:27:35 2019 +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-2019 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 "FrameRenderer.h"
+
+namespace Deprecated
+{
+  class ColorFrameRenderer : public FrameRenderer
+  {
+  private:
+    std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In RGB24
+
+  protected:
+    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
+
+  public:
+    ColorFrameRenderer(const Orthanc::ImageAccessor& frame,
+                       const OrthancStone::CoordinateSystem3D& framePlane,
+                       double pixelSpacingX,
+                       double pixelSpacingY,
+                       bool isFullQuality);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,162 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "DicomSeriesVolumeSlicer.h"
+
+#include "FrameRenderer.h"
+#include "../Toolbox/DicomFrameConverter.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace Deprecated
+{
+
+  void DicomSeriesVolumeSlicer::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
+  {
+    if (message.GetOrigin().GetSlicesCount() > 0)
+    {
+      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
+    }
+    else
+    {
+      BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
+    }
+  }
+
+  void DicomSeriesVolumeSlicer::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
+  {
+    BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
+  }
+
+
+  class DicomSeriesVolumeSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory
+  {
+  private:
+    const OrthancSlicesLoader::SliceImageReadyMessage&  message_;
+
+  public:
+    RendererFactory(const OrthancSlicesLoader::SliceImageReadyMessage& message) :
+      message_(message)
+    {
+    }
+
+    virtual ILayerRenderer* CreateRenderer() const
+    {
+      bool isFull = (message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPng ||
+                     message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPam);
+
+      return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull);
+    }
+  };
+
+  void DicomSeriesVolumeSlicer::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
+  {
+    // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache)
+    BroadcastMessage(FrameReadyMessage(*this, message.GetImage(), 
+                                  message.GetEffectiveQuality(), message.GetSlice()));
+
+    // then notify that the layer is ready for rendering
+    RendererFactory factory(message);
+    BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, message.GetSlice().GetGeometry()));
+  }
+
+  void DicomSeriesVolumeSlicer::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
+  {
+    BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, message.GetSlice().GetGeometry()));
+  }
+
+
+  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
+                                                   OrthancApiClient& orthanc) :
+    IVolumeSlicer(broker),
+    IObserver(broker),
+    loader_(broker, orthanc),
+    quality_(OrthancStone::SliceImageQuality_FullPng)
+  {
+    loader_.RegisterObserverCallback(
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage>
+        (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady));
+
+    loader_.RegisterObserverCallback(
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage>
+      (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError));
+
+    loader_.RegisterObserverCallback(
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage>
+        (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady));
+
+    loader_.RegisterObserverCallback(
+      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage>
+      (*this, &DicomSeriesVolumeSlicer::OnSliceImageError));
+  }
+
+  
+  void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId)
+  {
+    loader_.ScheduleLoadSeries(seriesId);
+  }
+
+
+  void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId)
+  {
+    loader_.ScheduleLoadInstance(instanceId);
+  }
+
+
+  void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId,
+                                          unsigned int frame)
+  {
+    loader_.ScheduleLoadFrame(instanceId, frame);
+  }
+
+
+  bool DicomSeriesVolumeSlicer::GetExtent(std::vector<OrthancStone::Vector>& points,
+                                          const OrthancStone::CoordinateSystem3D& viewportSlice)
+  {
+    size_t index;
+
+    if (loader_.IsGeometryReady() &&
+        loader_.LookupSlice(index, viewportSlice))
+    {
+      loader_.GetSlice(index).GetExtent(points);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  
+  void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
+  {
+    size_t index;
+
+    if (loader_.IsGeometryReady() &&
+        loader_.LookupSlice(index, viewportSlice))
+    {
+      loader_.ScheduleLoadSliceImage(index, quality_);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,127 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IVolumeSlicer.h"
+#include "../Toolbox/IWebService.h"
+#include "../Toolbox/OrthancSlicesLoader.h"
+#include "../Toolbox/OrthancApiClient.h"
+
+namespace Deprecated
+{  
+  // this class is in charge of loading a Frame.
+  // once it's been loaded (first the geometry and then the image),
+  // messages are sent to observers so they can use it
+  class DicomSeriesVolumeSlicer :
+    public IVolumeSlicer,
+    public OrthancStone::IObserver
+    //private OrthancSlicesLoader::ISliceLoaderObserver
+  {
+  public:
+    // TODO: Add "frame" and "instanceId"
+    class FrameReadyMessage : public OrthancStone::OriginMessage<DicomSeriesVolumeSlicer>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      const Orthanc::ImageAccessor&  frame_;
+      OrthancStone::SliceImageQuality              imageQuality_;
+      const Slice&                   slice_;
+
+    public:
+      FrameReadyMessage(DicomSeriesVolumeSlicer& origin,
+                        const Orthanc::ImageAccessor& frame,
+                        OrthancStone::SliceImageQuality imageQuality,
+                        const Slice& slice) :
+        OriginMessage(origin),
+        frame_(frame),
+        imageQuality_(imageQuality),
+        slice_(slice)
+      {
+      }
+
+      const Orthanc::ImageAccessor& GetFrame() const
+      {
+        return frame_;
+      }
+
+      OrthancStone::SliceImageQuality GetImageQuality() const
+      {
+        return imageQuality_;
+      }
+
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+    
+  private:
+    class RendererFactory;
+    
+    OrthancSlicesLoader  loader_;
+    OrthancStone::SliceImageQuality    quality_;
+
+  public:
+    DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
+                            OrthancApiClient& orthanc);
+
+    void LoadSeries(const std::string& seriesId);
+
+    void LoadInstance(const std::string& instanceId);
+
+    void LoadFrame(const std::string& instanceId,
+                   unsigned int frame);
+
+    void SetImageQuality(OrthancStone::SliceImageQuality quality)
+    {
+      quality_ = quality;
+    }
+
+    OrthancStone::SliceImageQuality GetImageQuality() const
+    {
+      return quality_;
+    }
+
+    size_t GetSlicesCount() const
+    {
+      return loader_.GetSlicesCount();
+    }
+
+    const Slice& GetSlice(size_t slice) const 
+    {
+      return loader_.GetSlice(slice);
+    }
+
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice);
+
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice);
+
+protected:
+    void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message);
+    void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message);
+    void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message);
+    void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,170 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "DicomStructureSetSlicer.h"
+
+namespace Deprecated
+{
+  class DicomStructureSetSlicer::Renderer : public ILayerRenderer
+  {
+  private:
+    class Structure
+    {
+    private:
+      bool                                                         visible_;
+      uint8_t                                                      red_;
+      uint8_t                                                      green_;
+      uint8_t                                                      blue_;
+      std::string                                                  name_;
+      std::vector< std::vector<OrthancStone::DicomStructureSet::PolygonPoint> >  polygons_;
+
+    public:
+      Structure(OrthancStone::DicomStructureSet& structureSet,
+                const OrthancStone::CoordinateSystem3D& plane,
+                size_t index) :
+        name_(structureSet.GetStructureName(index))
+      {
+        structureSet.GetStructureColor(red_, green_, blue_, index);
+        visible_ = structureSet.ProjectStructure(polygons_, index, plane);
+      }
+
+      void Render(OrthancStone::CairoContext& context)
+      {
+        if (visible_)
+        {
+          cairo_t* cr = context.GetObject();
+        
+          context.SetSourceColor(red_, green_, blue_);
+
+          for (size_t i = 0; i < polygons_.size(); i++)
+          {
+            cairo_move_to(cr, polygons_[i][0].first, polygons_[i][0].second);
+
+            for (size_t j = 1; j < polygons_[i].size(); j++)
+            {
+              cairo_line_to(cr, polygons_[i][j].first, polygons_[i][j].second);
+            }
+
+            cairo_line_to(cr, polygons_[i][0].first, polygons_[i][0].second);
+            cairo_stroke(cr);
+          }
+        }
+      }
+    };
+
+    typedef std::list<Structure*>  Structures;
+    
+    OrthancStone::CoordinateSystem3D  plane_;
+    Structures          structures_;
+    
+  public:
+    Renderer(OrthancStone::DicomStructureSet& structureSet,
+             const OrthancStone::CoordinateSystem3D& plane) :
+      plane_(plane)
+    {
+      for (size_t k = 0; k < structureSet.GetStructureCount(); k++)
+      {
+        structures_.push_back(new Structure(structureSet, plane, k));
+      }
+    }
+
+    virtual ~Renderer()
+    {
+      for (Structures::iterator it = structures_.begin();
+           it != structures_.end(); ++it)
+      {
+        delete *it;
+      }
+    }
+
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view)
+    {
+      cairo_set_line_width(context.GetObject(), 2.0f / view.GetZoom());
+
+      for (Structures::const_iterator it = structures_.begin();
+           it != structures_.end(); ++it)
+      {
+        assert(*it != NULL);
+        (*it)->Render(context);
+      }
+
+      return true;
+    }
+
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
+    {
+      return plane_;
+    }
+
+    virtual void SetLayerStyle(const RenderStyle& style)
+    {
+    }
+    
+    virtual bool IsFullQuality()
+    {
+      return true;
+    }
+  };
+
+
+  class DicomStructureSetSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory
+  {
+  private:
+    OrthancStone::DicomStructureSet&         structureSet_;
+    const OrthancStone::CoordinateSystem3D&  plane_;
+
+  public:
+    RendererFactory(OrthancStone::DicomStructureSet& structureSet,
+                    const OrthancStone::CoordinateSystem3D&  plane) :
+      structureSet_(structureSet),
+      plane_(plane)
+    {
+    }
+
+    virtual ILayerRenderer* CreateRenderer() const
+    {
+      return new Renderer(structureSet_, plane_);
+    }
+  };
+  
+
+  DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
+                                                   StructureSetLoader& loader) :
+    IVolumeSlicer(broker),
+    IObserver(broker),
+    loader_(loader)
+  {
+    loader_.RegisterObserverCallback(
+      new OrthancStone::Callable<DicomStructureSetSlicer, StructureSetLoader::ContentChangedMessage>
+      (*this, &DicomStructureSetSlicer::OnStructureSetLoaded));
+  }
+
+
+  void DicomStructureSetSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane)
+  {
+    if (loader_.HasStructureSet())
+    {
+      RendererFactory factory(loader_.GetStructureSet(), viewportPlane);
+      BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, viewportPlane));
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.h	Tue May 21 14:27:35 2019 +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-2019 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 "IVolumeSlicer.h"
+#include "../Volumes/StructureSetLoader.h"
+
+namespace Deprecated
+{
+  class DicomStructureSetSlicer :
+    public IVolumeSlicer,
+    public OrthancStone::IObserver
+  {
+  private:
+    class Renderer;
+    class RendererFactory;
+
+    StructureSetLoader& loader_;
+
+    void OnStructureSetLoaded(const IVolumeLoader::ContentChangedMessage& message)
+    {
+      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
+    }
+
+  public:
+    DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
+                            StructureSetLoader& loader);
+
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportPlane)
+    {
+      return false;
+    }
+
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/FrameRenderer.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,140 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "FrameRenderer.h"
+
+#include "GrayscaleFrameRenderer.h"
+#include "ColorFrameRenderer.h"
+
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  FrameRenderer::FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane,
+                               double pixelSpacingX,
+                               double pixelSpacingY,
+                               bool isFullQuality) :
+    framePlane_(framePlane),
+    pixelSpacingX_(pixelSpacingX),
+    pixelSpacingY_(pixelSpacingY),
+    isFullQuality_(isFullQuality)
+  {
+  }
+
+
+  bool FrameRenderer::RenderLayer(OrthancStone::CairoContext& context,
+                                  const ViewportGeometry& view)
+  {    
+    if (!style_.visible_)
+    {
+      return true;
+    }
+
+    if (display_.get() == NULL)
+    {
+      display_.reset(GenerateDisplay(style_));
+    }
+
+    assert(display_.get() != NULL);
+
+    cairo_t *cr = context.GetObject();
+
+    cairo_save(cr);
+
+    cairo_matrix_t transform;
+    cairo_matrix_init_identity(&transform);
+    cairo_matrix_scale(&transform, pixelSpacingX_, pixelSpacingY_);
+    cairo_matrix_translate(&transform, -0.5, -0.5);
+    cairo_transform(cr, &transform);
+
+    //cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+    cairo_set_source_surface(cr, display_->GetObject(), 0, 0);
+
+    switch (style_.interpolation_)
+    {
+      case OrthancStone::ImageInterpolation_Nearest:
+        cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
+        break;
+
+      case OrthancStone::ImageInterpolation_Bilinear:
+        cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR);
+        break;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    cairo_paint_with_alpha(cr, style_.alpha_);
+
+    if (style_.drawGrid_)
+    {
+      context.SetSourceColor(style_.drawColor_);
+      cairo_set_line_width(cr, 0.5 / view.GetZoom());
+
+      for (unsigned int x = 0; x <= display_->GetWidth(); x++)
+      {
+        cairo_move_to(cr, x, 0);
+        cairo_line_to(cr, x, display_->GetHeight());
+      }
+
+      for (unsigned int y = 0; y <= display_->GetHeight(); y++)
+      {
+        cairo_move_to(cr, 0, y);
+        cairo_line_to(cr, display_->GetWidth(), y);
+      }
+
+      cairo_stroke(cr);
+    }
+
+    cairo_restore(cr);
+
+    return true;
+  }
+
+
+  void FrameRenderer::SetLayerStyle(const RenderStyle& style)
+  {
+    style_ = style;
+    display_.reset(NULL);
+  }
+
+
+  ILayerRenderer* FrameRenderer::CreateRenderer(const Orthanc::ImageAccessor& frame,
+                                                const Deprecated::Slice& framePlane,
+                                                bool isFullQuality)
+  {
+    if (frame.GetFormat() == Orthanc::PixelFormat_RGB24)
+    {
+      return new ColorFrameRenderer(frame,
+                                    framePlane.GetGeometry(), 
+                                    framePlane.GetPixelSpacingX(),
+                                    framePlane.GetPixelSpacingY(), isFullQuality);
+    }
+    else
+    {
+      return new GrayscaleFrameRenderer(frame,
+                                        framePlane.GetConverter(),
+                                        framePlane.GetGeometry(), 
+                                        framePlane.GetPixelSpacingX(),
+                                        framePlane.GetPixelSpacingY(), isFullQuality);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/FrameRenderer.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,69 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ILayerRenderer.h"
+
+#include "../Toolbox/Slice.h"
+
+namespace Deprecated
+{
+  class FrameRenderer : public ILayerRenderer
+  {
+  private:
+    OrthancStone::CoordinateSystem3D            framePlane_;
+    double                        pixelSpacingX_;
+    double                        pixelSpacingY_;
+    RenderStyle                   style_;
+    bool                          isFullQuality_;
+    std::auto_ptr<OrthancStone::CairoSurface>   display_;
+
+  protected:
+    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style) = 0;
+
+  public:
+    FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane,
+                  double pixelSpacingX,
+                  double pixelSpacingY,
+                  bool isFullQuality);
+
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view);
+
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
+    {
+      return framePlane_;
+    }
+
+    virtual void SetLayerStyle(const RenderStyle& style);
+
+    virtual bool IsFullQuality() 
+    {
+      return isFullQuality_;
+    }
+
+    // TODO: Avoid cloning the "frame"
+    static ILayerRenderer* CreateRenderer(const Orthanc::ImageAccessor& frame,
+                                          const Deprecated::Slice& framePlane,
+                                          bool isFullQuality);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,141 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "GrayscaleFrameRenderer.h"
+
+#include <Core/Images/Image.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  OrthancStone::CairoSurface* GrayscaleFrameRenderer::GenerateDisplay(const RenderStyle& style)
+  {
+    assert(frame_->GetFormat() == Orthanc::PixelFormat_Float32);
+
+    std::auto_ptr<OrthancStone::CairoSurface> result;
+
+    float windowCenter, windowWidth;
+    style.ComputeWindowing(windowCenter, windowWidth,
+                           defaultWindowCenter_, defaultWindowWidth_);
+
+    float x0 = windowCenter - windowWidth / 2.0f;
+    float x1 = windowCenter + windowWidth / 2.0f;
+
+    //LOG(INFO) << "Window: " << x0 << " => " << x1;
+
+    result.reset(new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
+
+    const uint8_t* lut = NULL;
+    if (style.applyLut_)
+    {
+      if (Orthanc::EmbeddedResources::GetFileResourceSize(style.lut_) != 3 * 256)
+      {
+        // Invalid colormap
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+
+      lut = reinterpret_cast<const uint8_t*>(Orthanc::EmbeddedResources::GetFileResourceBuffer(style.lut_));
+    }
+
+    Orthanc::ImageAccessor target;
+    result->GetWriteableAccessor(target);
+    
+    const unsigned int width = target.GetWidth();
+    const unsigned int height = target.GetHeight();
+    
+    for (unsigned int y = 0; y < height; y++)
+    {
+      const float* p = reinterpret_cast<const float*>(frame_->GetConstRow(y));
+      uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+
+      for (unsigned int x = 0; x < width; x++, p++, q += 4)
+      {
+        uint8_t v = 0;
+        if (windowWidth >= 0.001f)  // Avoid division by zero
+        {
+          if (*p >= x1)
+          {
+            v = 255;
+          }
+          else if (*p <= x0)
+          {
+            v = 0;
+          }
+          else
+          {
+            // https://en.wikipedia.org/wiki/Linear_interpolation
+            v = static_cast<uint8_t>(255.0f * (*p - x0) / (x1 - x0));
+          }
+
+          if (style.reverse_ ^ (photometric_ == Orthanc::PhotometricInterpretation_Monochrome1))
+          {
+            v = 255 - v;
+          }
+        }
+
+        if (style.applyLut_)
+        {
+          assert(lut != NULL);
+          q[3] = 255;
+          q[2] = lut[3 * v];
+          q[1] = lut[3 * v + 1];
+          q[0] = lut[3 * v + 2];
+        }
+        else
+        {
+          q[3] = 255;
+          q[2] = v;
+          q[1] = v;
+          q[0] = v;
+        }
+      }
+    }
+
+    return result.release();
+  }
+
+
+  GrayscaleFrameRenderer::GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame,
+                                                 const Deprecated::DicomFrameConverter& converter,
+                                                 const OrthancStone::CoordinateSystem3D& framePlane,
+                                                 double pixelSpacingX,
+                                                 double pixelSpacingY,
+                                                 bool isFullQuality) :
+    FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality),
+    frame_(Orthanc::Image::Clone(frame)),
+    defaultWindowCenter_(static_cast<float>(converter.GetDefaultWindowCenter())),
+    defaultWindowWidth_(static_cast<float>(converter.GetDefaultWindowWidth())),
+    photometric_(converter.GetPhotometricInterpretation())
+  {
+    if (frame_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    converter.ConvertFrameInplace(frame_);
+    assert(frame_.get() != NULL);
+
+    if (frame_->GetFormat() != Orthanc::PixelFormat_Float32)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/GrayscaleFrameRenderer.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,48 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "FrameRenderer.h"
+#include "../Toolbox/DicomFrameConverter.h"
+
+namespace Deprecated
+{
+  class GrayscaleFrameRenderer : public FrameRenderer
+  {
+  private:
+    std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In Float32
+    float                                   defaultWindowCenter_;
+    float                                   defaultWindowWidth_;
+    Orthanc::PhotometricInterpretation      photometric_;
+
+  protected:
+    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
+
+  public:
+    GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame,
+                           const Deprecated::DicomFrameConverter& converter,
+                           const OrthancStone::CoordinateSystem3D& framePlane,
+                           double pixelSpacingX,
+                           double pixelSpacingY,
+                           bool isFullQuality);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/ILayerRenderer.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,47 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Viewport/CairoContext.h"
+#include "../../Toolbox/CoordinateSystem3D.h"
+#include "../Toolbox/ViewportGeometry.h"
+#include "RenderStyle.h"
+
+namespace Deprecated
+{
+  class ILayerRenderer : public boost::noncopyable
+  {
+  public:
+    virtual ~ILayerRenderer()
+    {
+    }
+    
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view) = 0;
+
+    virtual void SetLayerStyle(const RenderStyle& style) = 0;
+
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() = 0;
+    
+    virtual bool IsFullQuality() = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/IVolumeSlicer.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,139 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ILayerRenderer.h"
+#include "../Toolbox/Slice.h"
+#include "../../Messages/IObservable.h"
+#include "../../Messages/IMessage.h"
+#include "Core/Images/Image.h"
+#include <boost/shared_ptr.hpp>
+
+namespace Deprecated
+{
+  class IVolumeSlicer : public OrthancStone::IObservable
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeSlicer);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeSlicer);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeSlicer);
+
+    class SliceContentChangedMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      const Deprecated::Slice& slice_;
+
+    public:
+      SliceContentChangedMessage(IVolumeSlicer& origin,
+                                 const Deprecated::Slice& slice) :
+        OriginMessage(origin),
+        slice_(slice)
+      {
+      }
+
+      const Deprecated::Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+    
+
+    class LayerReadyMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    public:
+      class IRendererFactory : public boost::noncopyable
+      {
+      public:
+        virtual ~IRendererFactory()
+        {
+        }
+
+        virtual ILayerRenderer* CreateRenderer() const = 0;
+      };
+    
+    private:
+      const IRendererFactory&    factory_;
+      const OrthancStone::CoordinateSystem3D&  slice_;
+
+    public:
+      LayerReadyMessage(IVolumeSlicer& origin,
+                        const IRendererFactory& rendererFactory,
+                        const OrthancStone::CoordinateSystem3D& slice) :
+        OriginMessage(origin),
+        factory_(rendererFactory),
+        slice_(slice)
+      {
+      }
+
+      ILayerRenderer* CreateRenderer() const
+      {
+        return factory_.CreateRenderer();
+      }
+
+      const OrthancStone::CoordinateSystem3D& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+
+    class LayerErrorMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      const OrthancStone::CoordinateSystem3D&  slice_;
+
+    public:
+      LayerErrorMessage(IVolumeSlicer& origin,
+                        const OrthancStone::CoordinateSystem3D& slice) :
+        OriginMessage(origin),
+        slice_(slice)
+      {
+      }
+
+      const OrthancStone::CoordinateSystem3D& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+
+    IVolumeSlicer(OrthancStone::MessageBroker& broker) :
+      IObservable(broker)
+    {
+    }
+    
+    virtual ~IVolumeSlicer()
+    {
+    }
+
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice) = 0;
+
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/LineLayerRenderer.cpp	Tue May 21 14:27:35 2019 +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-2019 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 "LineLayerRenderer.h"
+
+namespace Deprecated
+{
+  LineLayerRenderer::LineLayerRenderer(double x1,
+                                       double y1,
+                                       double x2,
+                                       double y2,
+                                       const OrthancStone::CoordinateSystem3D& plane) : 
+    x1_(x1),
+    y1_(y1),
+    x2_(x2),
+    y2_(y2),
+    plane_(plane)
+  {
+    RenderStyle style;
+    SetLayerStyle(style);
+  }
+
+
+  bool LineLayerRenderer::RenderLayer(OrthancStone::CairoContext& context,
+                                      const ViewportGeometry& view)
+  {
+    if (visible_)
+    {
+      context.SetSourceColor(color_);
+
+      cairo_t *cr = context.GetObject();
+      cairo_set_line_width(cr, 1.0 / view.GetZoom());
+      cairo_move_to(cr, x1_, y1_);
+      cairo_line_to(cr, x2_, y2_);
+      cairo_stroke(cr);
+    }
+
+    return true;
+  }
+
+
+  void LineLayerRenderer::SetLayerStyle(const RenderStyle& style)
+  {
+    visible_ = style.visible_;
+    color_[0] = style.drawColor_[0];
+    color_[1] = style.drawColor_[1];
+    color_[2] = style.drawColor_[2];
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/LineLayerRenderer.h	Tue May 21 14:27:35 2019 +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-2019 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 "ILayerRenderer.h"
+
+namespace Deprecated
+{
+  class LineLayerRenderer : public ILayerRenderer
+  {
+  private:
+    double              x1_;
+    double              y1_;
+    double              x2_;
+    double              y2_;
+    OrthancStone::CoordinateSystem3D  plane_;
+    bool                visible_;
+    uint8_t             color_[3];
+
+  public:
+    LineLayerRenderer(double x1,
+                      double y1,
+                      double x2,
+                      double y2,
+                      const OrthancStone::CoordinateSystem3D& plane);
+
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view);
+
+    virtual void SetLayerStyle(const RenderStyle& style);
+
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
+    {
+      return plane_;
+    }
+    
+    virtual bool IsFullQuality()
+    {
+      return true;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/LineMeasureTracker.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,102 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "LineMeasureTracker.h"
+
+#include <stdio.h>
+
+namespace Deprecated
+{
+  LineMeasureTracker::LineMeasureTracker(IStatusBar* statusBar,
+                                         const OrthancStone::CoordinateSystem3D& slice,
+                                         double x, 
+                                         double y,
+                                         uint8_t red,
+                                         uint8_t green,
+                                         uint8_t blue,
+                                         const Orthanc::Font& font) :
+    statusBar_(statusBar),
+    slice_(slice),
+    x1_(x),
+    y1_(y),
+    x2_(x),
+    y2_(y),
+    font_(font)
+  {
+    color_[0] = red;
+    color_[1] = green;
+    color_[2] = blue;
+  }
+    
+
+  void LineMeasureTracker::Render(OrthancStone::CairoContext& context,
+                                  double zoom)
+  {
+    context.SetSourceColor(color_[0], color_[1], color_[2]);
+
+    cairo_t* cr = context.GetObject();
+    cairo_set_line_width(cr, 2.0 / zoom);
+    cairo_move_to(cr, x1_, y1_);
+    cairo_line_to(cr, x2_, y2_);
+    cairo_stroke(cr);
+
+    if (y2_ - y1_ < 0)
+    {
+      context.DrawText(font_, FormatLength(), x2_, y2_ - 5, OrthancStone::BitmapAnchor_BottomCenter);
+    }
+    else
+    {
+      context.DrawText(font_, FormatLength(), x2_, y2_ + 5, OrthancStone::BitmapAnchor_TopCenter);
+    }
+  }
+    
+
+  double LineMeasureTracker::GetLength() const  // In millimeters
+  {
+    OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
+    OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
+    return boost::numeric::ublas::norm_2(b - a);
+  }
+
+
+  std::string LineMeasureTracker::FormatLength() const
+  {
+    char buf[64];
+    sprintf(buf, "%0.01f cm", GetLength() / 10.0);
+    return buf;
+  }
+
+  void LineMeasureTracker::MouseMove(int displayX,
+                                     int displayY,
+                                     double x,
+                                     double y,
+                                     const std::vector<Touch>& displayTouches,
+                                     const std::vector<Touch>& sceneTouches)
+  {
+    x2_ = x;
+    y2_ = y;
+
+    if (statusBar_ != NULL)
+    {
+      statusBar_->SetMessage("Line length: " + FormatLength());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/LineMeasureTracker.h	Tue May 21 14:27:35 2019 +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-2019 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 "../Widgets/IWorldSceneMouseTracker.h"
+
+#include "../Viewport/IStatusBar.h"
+#include "../../Toolbox/CoordinateSystem3D.h"
+
+namespace Deprecated
+{
+  class LineMeasureTracker : public IWorldSceneMouseTracker
+  {
+  private:
+    IStatusBar*           statusBar_;
+    OrthancStone::CoordinateSystem3D    slice_;
+    double                x1_;
+    double                y1_;
+    double                x2_;
+    double                y2_;
+    uint8_t               color_[3];
+    unsigned int          fontSize_;
+    const Orthanc::Font&  font_;
+
+  public:
+    LineMeasureTracker(IStatusBar* statusBar,
+                       const OrthancStone::CoordinateSystem3D& slice,
+                       double x, 
+                       double y,
+                       uint8_t red,
+                       uint8_t green,
+                       uint8_t blue,
+                       const Orthanc::Font& font);
+
+    virtual bool HasRender() const
+    {
+      return true;
+    }
+
+    virtual void Render(OrthancStone::CairoContext& context,
+                        double zoom);
+    
+    double GetLength() const;  // In millimeters
+
+    std::string FormatLength() const;
+
+    virtual void MouseUp()
+    {
+      // Possibly create a new landmark "volume" with the line in subclasses
+    }
+
+    virtual void MouseMove(int displayX,
+                           int displayY,
+                           double x,
+                           double y,
+                           const std::vector<Touch>& displayTouches,
+                           const std::vector<Touch>& sceneTouches);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/RenderStyle.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,73 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "RenderStyle.h"
+
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  RenderStyle::RenderStyle()
+  {
+    visible_ = true;
+    reverse_ = false;
+    windowing_ = OrthancStone::ImageWindowing_Custom;
+    alpha_ = 1;
+    applyLut_ = false;
+    lut_ = Orthanc::EmbeddedResources::COLORMAP_HOT;
+    drawGrid_ = false;
+    drawColor_[0] = 255;
+    drawColor_[1] = 255;
+    drawColor_[2] = 255;
+    customWindowCenter_ = 128;
+    customWindowWidth_ = 256;
+    interpolation_ = OrthancStone::ImageInterpolation_Nearest;
+    fontSize_ = 14;
+  }
+
+
+  void RenderStyle::ComputeWindowing(float& targetCenter,
+                                     float& targetWidth,
+                                     float defaultCenter,
+                                     float defaultWidth) const
+  {
+    if (windowing_ == OrthancStone::ImageWindowing_Custom)
+    {
+      targetCenter = customWindowCenter_;
+      targetWidth = customWindowWidth_;
+    }
+    else
+    {
+      return ::OrthancStone::ComputeWindowing
+        (targetCenter, targetWidth, windowing_, defaultCenter, defaultWidth);
+    }
+  }
+
+  
+  void RenderStyle::SetColor(uint8_t red,
+                             uint8_t green,
+                             uint8_t blue)
+  {
+    drawColor_[0] = red;
+    drawColor_[1] = green;
+    drawColor_[2] = blue;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/RenderStyle.h	Tue May 21 14:27:35 2019 +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-2019 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 "../../StoneEnumerations.h"
+
+#include <EmbeddedResources.h>
+
+#include <stdint.h>
+
+namespace Deprecated
+{
+  struct RenderStyle
+  {
+    bool visible_;
+    bool reverse_;
+    OrthancStone::ImageWindowing windowing_;
+    float alpha_;   // In [0,1]
+    bool applyLut_;
+    Orthanc::EmbeddedResources::FileResourceId  lut_;
+    bool drawGrid_;
+    uint8_t drawColor_[3];
+    float customWindowCenter_;
+    float customWindowWidth_;
+    OrthancStone::ImageInterpolation interpolation_;
+    unsigned int fontSize_;
+    
+    RenderStyle();
+
+    void ComputeWindowing(float& targetCenter,
+                          float& targetWidth,
+                          float defaultCenter,
+                          float defaultWidth) const;
+
+    void SetColor(uint8_t red,
+                  uint8_t green,
+                  uint8_t blue);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/SeriesFrameRendererFactory.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,177 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "SeriesFrameRendererFactory.h"
+
+#include "FrameRenderer.h"
+
+#include <OrthancException.h>
+#include <Logging.h>
+#include <Toolbox.h>
+#include <Plugins/Samples/Common/OrthancPluginException.h>
+#include <Plugins/Samples/Common/DicomDatasetReader.h>
+
+
+namespace Deprecated
+{
+  void SeriesFrameRendererFactory::ReadCurrentFrameDataset(size_t frame)
+  {
+    if (currentDataset_.get() != NULL &&
+        (fast_ || currentFrame_ == frame))
+    {
+      // The frame has not changed since the previous call, no need to
+      // update the DICOM dataset
+      return; 
+    }
+      
+    currentDataset_.reset(loader_->DownloadDicom(frame));
+    currentFrame_ = frame;
+
+    if (currentDataset_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+
+  void SeriesFrameRendererFactory::GetCurrentPixelSpacing(double& spacingX,
+                                                          double& spacingY) const
+  {
+    if (currentDataset_.get() == NULL)
+    {
+      // There was no previous call "ReadCurrentFrameDataset()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+    
+    GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *currentDataset_);
+  }
+
+
+  double SeriesFrameRendererFactory::GetCurrentSliceThickness() const
+  {
+    if (currentDataset_.get() == NULL)
+    {
+      // There was no previous call "ReadCurrentFrameDataset()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+    
+    try
+    {
+      OrthancPlugins::DicomDatasetReader reader(*currentDataset_);
+
+      double thickness;
+      if (reader.GetDoubleValue(thickness, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
+      {
+        return thickness;
+      }
+    }
+    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
+    {
+    }
+
+    // Some arbitrary large slice thickness
+    return std::numeric_limits<double>::infinity();
+  }
+
+
+  SeriesFrameRendererFactory::SeriesFrameRendererFactory(ISeriesLoader* loader,   // Takes ownership
+                                                         bool fast) :
+    loader_(loader),
+    currentFrame_(0),
+    fast_(fast)
+  {
+    if (loader == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+
+  bool SeriesFrameRendererFactory::GetExtent(double& x1,
+                                             double& y1,
+                                             double& x2,
+                                             double& y2,
+                                             const SliceGeometry& viewportSlice)
+  {
+    if (currentDataset_.get() == NULL)
+    {
+      // There has been no previous call to
+      // "CreateLayerRenderer". Read some arbitrary DICOM frame, the
+      // one at the middle of the series.
+      unsigned int depth = loader_->GetGeometry().GetSliceCount();
+      ReadCurrentFrameDataset(depth / 2);
+    }
+
+    double spacingX, spacingY;
+    GetCurrentPixelSpacing(spacingX, spacingY);
+
+    return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2, 
+                                             viewportSlice, 
+                                             loader_->GetGeometry().GetSlice(0), 
+                                             loader_->GetWidth(), 
+                                             loader_->GetHeight(),
+                                             spacingX, spacingY);
+  }
+
+
+  ILayerRenderer* SeriesFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice)
+  {
+    size_t closest;
+    double distance;
+
+    bool isOpposite;
+    if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, loader_->GetGeometry().GetNormal(), viewportSlice.GetNormal()) ||
+        !loader_->GetGeometry().ComputeClosestSlice(closest, distance, viewportSlice.GetOrigin()))
+    {
+      // Unable to compute the slice in the series that is the
+      // closest to the slice displayed by the viewport
+      return NULL;
+    }
+
+    ReadCurrentFrameDataset(closest);
+    assert(currentDataset_.get() != NULL);
+        
+    double spacingX, spacingY;
+    GetCurrentPixelSpacing(spacingX, spacingY);
+
+    if (distance <= GetCurrentSliceThickness() / 2.0)
+    {
+      SliceGeometry frameSlice(*currentDataset_);
+      return FrameRenderer::CreateRenderer(loader_->DownloadFrame(closest), 
+                                           frameSlice,
+                                           *currentDataset_, 
+                                           spacingX, spacingY,
+                                           true);
+    }
+    else
+    {
+      // The closest slice of the series is too far away from the
+      // slice displayed by the viewport
+      return NULL;
+    }
+  }
+
+
+  ISliceableVolume& SeriesFrameRendererFactory::GetSourceVolume() const
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/SeriesFrameRendererFactory.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,65 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ILayerRendererFactory.h"
+
+#include "../Toolbox/ISeriesLoader.h"
+
+namespace Deprecated
+{
+  class SeriesFrameRendererFactory : public ILayerRendererFactory
+  {
+  private:
+    std::auto_ptr<ISeriesLoader>  loader_;
+    size_t                        currentFrame_;
+    bool                          fast_;
+
+    std::auto_ptr<OrthancPlugins::IDicomDataset>  currentDataset_;
+
+    void ReadCurrentFrameDataset(size_t frame);
+
+    void GetCurrentPixelSpacing(double& spacingX,
+                                double& spacingY) const;
+
+    double GetCurrentSliceThickness() const;
+
+  public:
+    SeriesFrameRendererFactory(ISeriesLoader* loader,   // Takes ownership
+                               bool fast);
+
+    virtual bool GetExtent(double& x1,
+                           double& y1,
+                           double& x2,
+                           double& y2,
+                           const SliceGeometry& viewportSlice);
+
+    virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice);
+
+    virtual bool HasSourceVolume() const
+    {
+      return false;
+    }
+
+    virtual ISliceableVolume& GetSourceVolume() const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/SingleFrameRendererFactory.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,88 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "SingleFrameRendererFactory.h"
+
+#include "FrameRenderer.h"
+#include "../Toolbox/MessagingToolbox.h"
+#include "../Toolbox/DicomFrameConverter.h"
+
+#include <OrthancException.h>
+#include <Plugins/Samples/Common/FullOrthancDataset.h>
+#include <Plugins/Samples/Common/DicomDatasetReader.h>
+
+namespace Deprecated
+{
+  SingleFrameRendererFactory::SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc,
+                                                         const std::string& instanceId,
+                                                         unsigned int frame) :
+    orthanc_(orthanc),
+    instance_(instanceId),
+    frame_(frame)
+  {
+    dicom_.reset(new OrthancPlugins::FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags"));
+
+    DicomFrameConverter converter;
+    converter.ReadParameters(*dicom_);
+    format_ = converter.GetExpectedPixelFormat();
+  }
+
+
+  bool SingleFrameRendererFactory::GetExtent(double& x1,
+                                             double& y1,
+                                             double& x2,
+                                             double& y2,
+                                             const SliceGeometry& viewportSlice)
+  {
+    // Assume that PixelSpacingX == PixelSpacingY == 1
+
+    OrthancPlugins::DicomDatasetReader reader(*dicom_);
+
+    unsigned int width, height;
+
+    if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) ||
+        !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    x1 = 0;
+    y1 = 0;
+    x2 = static_cast<double>(width);
+    y2 = static_cast<double>(height);
+
+    return true;
+  }
+
+
+  ILayerRenderer* SingleFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice)
+  {
+    SliceGeometry frameSlice(*dicom_);
+    return FrameRenderer::CreateRenderer(MessagingToolbox::DecodeFrame(orthanc_, instance_, frame_, format_), 
+                                         frameSlice, *dicom_, 1, 1, true);
+  }
+
+
+  ISliceableVolume& SingleFrameRendererFactory::GetSourceVolume() const
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/SingleFrameRendererFactory.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,69 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ILayerRendererFactory.h"
+#include <Plugins/Samples/Common/IOrthancConnection.h>
+
+namespace Deprecated
+{
+  class SingleFrameRendererFactory : public ILayerRendererFactory
+  {
+  private:
+    OrthancPlugins::IOrthancConnection&           orthanc_;
+    std::auto_ptr<OrthancPlugins::IDicomDataset>  dicom_;
+
+    std::string           instance_;
+    unsigned int          frame_;
+    Orthanc::PixelFormat  format_;
+
+  public:
+    SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc,
+                               const std::string& instanceId,
+                               unsigned int frame);
+
+    const OrthancPlugins::IDicomDataset& GetDataset() const
+    {
+      return *dicom_;
+    }
+
+    SliceGeometry GetSliceGeometry()
+    {
+      return SliceGeometry(*dicom_);
+    }
+
+    virtual bool GetExtent(double& x1,
+                           double& y1,
+                           double& x2,
+                           double& y2,
+                           const SliceGeometry& viewportSlice);
+
+    virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice);
+
+    virtual bool HasSourceVolume() const
+    {
+      return false;
+    }
+
+    virtual ISliceableVolume& GetSourceVolume() const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/SliceOutlineRenderer.cpp	Tue May 21 14:27:35 2019 +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-2019 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 "SliceOutlineRenderer.h"
+
+namespace Deprecated
+{
+  bool SliceOutlineRenderer::RenderLayer(OrthancStone::CairoContext& context,
+                                         const ViewportGeometry& view)
+  {
+    if (style_.visible_)
+    {
+      cairo_t *cr = context.GetObject();
+      cairo_save(cr);
+
+      context.SetSourceColor(style_.drawColor_);
+
+      double x1 = -0.5 * pixelSpacingX_;
+      double y1 = -0.5 * pixelSpacingY_;
+        
+      cairo_set_line_width(cr, 1.0 / view.GetZoom());
+      cairo_rectangle(cr, x1, y1,
+                      static_cast<double>(width_) * pixelSpacingX_,
+                      static_cast<double>(height_) * pixelSpacingY_);
+
+      double handleSize = 10.0f / view.GetZoom();
+      cairo_move_to(cr, x1 + handleSize, y1);
+      cairo_line_to(cr, x1, y1 + handleSize);
+
+      cairo_stroke(cr);
+      cairo_restore(cr);
+    }
+
+    return true;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Layers/SliceOutlineRenderer.h	Tue May 21 14:27:35 2019 +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-2019 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 "ILayerRenderer.h"
+#include "../Toolbox/Slice.h"
+
+namespace Deprecated
+{
+  class SliceOutlineRenderer : public ILayerRenderer
+  {
+  private:
+    OrthancStone::CoordinateSystem3D  geometry_;
+    double              pixelSpacingX_;
+    double              pixelSpacingY_;
+    unsigned int        width_;
+    unsigned int        height_;
+    RenderStyle         style_;
+
+  public:
+    SliceOutlineRenderer(const Slice& slice) :
+      geometry_(slice.GetGeometry()),
+      pixelSpacingX_(slice.GetPixelSpacingX()),
+      pixelSpacingY_(slice.GetPixelSpacingY()),
+      width_(slice.GetWidth()),
+      height_(slice.GetHeight())
+    {
+    }
+
+    virtual bool RenderLayer(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view);
+
+    virtual void SetLayerStyle(const RenderStyle& style)
+    {
+      style_ = style;
+    }
+
+    virtual const OrthancStone::CoordinateSystem3D& GetLayerSlice()
+    {
+      return geometry_;
+    }
+
+    virtual bool IsFullQuality()
+    {
+      return true;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/SmartLoader.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,292 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "SmartLoader.h"
+
+#include "../Messages/MessageForwarder.h"
+#include "../StoneException.h"
+#include "Core/Images/Image.h"
+#include "Core/Logging.h"
+#include "Layers/DicomSeriesVolumeSlicer.h"
+#include "Layers/FrameRenderer.h"
+#include "Widgets/SliceViewerWidget.h"
+
+namespace Deprecated
+{
+  enum CachedSliceStatus
+  {
+    CachedSliceStatus_ScheduledToLoad,
+    CachedSliceStatus_GeometryLoaded,
+    CachedSliceStatus_ImageLoaded
+  };
+
+  class SmartLoader::CachedSlice : public IVolumeSlicer
+  {
+  public:
+    class RendererFactory : public LayerReadyMessage::IRendererFactory
+    {
+    private:
+      const CachedSlice&  that_;
+
+    public:
+      RendererFactory(const CachedSlice& that) :
+        that_(that)
+      {
+      }
+
+      virtual ILayerRenderer* CreateRenderer() const
+      {
+        bool isFull = (that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPng ||
+                       that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPam);
+
+        return FrameRenderer::CreateRenderer(*that_.image_, *that_.slice_, isFull);
+      }
+    };
+    
+    unsigned int                    sliceIndex_;
+    std::auto_ptr<Slice>            slice_;
+    boost::shared_ptr<Orthanc::ImageAccessor>   image_;
+    OrthancStone::SliceImageQuality               effectiveQuality_;
+    CachedSliceStatus               status_;
+
+  public:
+    CachedSlice(OrthancStone::MessageBroker& broker) :
+    IVolumeSlicer(broker)
+    {
+    }
+
+    virtual ~CachedSlice()
+    {
+    }
+
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice)
+    {
+      // TODO: viewportSlice is not used !!!!
+      slice_->GetExtent(points);
+      return true;
+    }
+
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
+    {
+      // TODO: viewportSlice is not used !!!!
+
+      // it has already been loaded -> trigger the "layer ready" message immediately otherwise, do nothing now.  The LayerReady will be triggered
+      // once the VolumeSlicer is ready
+      if (status_ == CachedSliceStatus_ImageLoaded)
+      {
+        LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId();
+
+        RendererFactory factory(*this);   
+        BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry()));
+      }
+      else
+      {
+        LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is not loaded yet): " << slice_->GetOrthancInstanceId();
+      }
+    }
+
+    CachedSlice* Clone() const
+    {
+      CachedSlice* output = new CachedSlice(GetBroker());
+      output->sliceIndex_ = sliceIndex_;
+      output->slice_.reset(slice_->Clone());
+      output->image_ = image_;
+      output->effectiveQuality_ = effectiveQuality_;
+      output->status_ = status_;
+
+      return output;
+    }
+
+  };
+
+
+  SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker,  
+                           OrthancApiClient& orthancApiClient) :
+    IObservable(broker),
+    IObserver(broker),
+    imageQuality_(OrthancStone::SliceImageQuality_FullPam),
+    orthancApiClient_(orthancApiClient)
+  {
+  }
+
+  void SmartLoader::SetFrameInWidget(SliceViewerWidget& sliceViewer, 
+                                     size_t layerIndex, 
+                                     const std::string& instanceId, 
+                                     unsigned int frame)
+  {
+    // TODO: check if this frame has already been loaded or is already being loaded.
+    // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately"
+    //   (it can not be immediate because Observers needs to register first and this is done after this method returns)
+    // - if currently loading, we need to return an object that will observe the existing VolumeSlicer and forward
+    //   the messages to its observables
+    // in both cases, we must be carefull about objects lifecycle !!!
+
+    std::auto_ptr<IVolumeSlicer> layerSource;
+    std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
+    SmartLoader::CachedSlice* cachedSlice = NULL;
+
+    if (cachedSlices_.find(sliceKeyId) != cachedSlices_.end()) // && cachedSlices_[sliceKeyId]->status_ == CachedSliceStatus_Loaded)
+    {
+      layerSource.reset(cachedSlices_[sliceKeyId]->Clone());
+      cachedSlice = dynamic_cast<SmartLoader::CachedSlice*>(layerSource.get());
+    }
+    else
+    {
+      layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
+      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
+      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
+      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
+      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
+      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
+    }
+
+    // make sure that the widget registers the events before we trigger them
+    if (sliceViewer.GetLayerCount() == layerIndex)
+    {
+      sliceViewer.AddLayer(layerSource.release());
+    }
+    else if (sliceViewer.GetLayerCount() > layerIndex)
+    {
+      sliceViewer.ReplaceLayer(layerIndex, layerSource.release());
+    }
+    else
+    {
+      throw OrthancStone::StoneException(OrthancStone::ErrorCode_CanOnlyAddOneLayerAtATime);
+    }
+
+    if (cachedSlice != NULL)
+    {
+      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice));
+    }
+
+  }
+
+  void SmartLoader::PreloadSlice(const std::string instanceId, 
+                                 unsigned int frame)
+  {
+    // TODO: reactivate -> need to be able to ScheduleLayerLoading in IVolumeSlicer without calling ScheduleLayerCreation
+    return;
+    // TODO: check if it is already in the cache
+
+
+
+    // create the slice in the cache with "empty" data
+    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
+    cachedSlice->slice_.reset(new Slice(instanceId, frame));
+    cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad;
+    std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
+
+    LOG(WARNING) << "Will preload: " << sliceKeyId;
+
+    cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
+
+    std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
+
+    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
+    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
+    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
+    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
+    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
+
+    // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache
+    preloadingInstances_[sliceKeyId] = boost::shared_ptr<IVolumeSlicer>(layerSource.release());
+  }
+
+
+//  void PreloadStudy(const std::string studyId)
+//  {
+//    /* TODO */
+//  }
+
+//  void PreloadSeries(const std::string seriesId)
+//  {
+//    /* TODO */
+//  }
+
+
+  void SmartLoader::OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
+  {
+    const DicomSeriesVolumeSlicer& source =
+      dynamic_cast<const DicomSeriesVolumeSlicer&>(message.GetOrigin());
+
+    // save/replace the slice in cache
+    const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount()
+    std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
+                              boost::lexical_cast<std::string>(slice.GetFrame()));
+
+    LOG(WARNING) << "Geometry ready: " << sliceKeyId;
+
+    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
+    cachedSlice->slice_.reset(slice.Clone());
+    cachedSlice->effectiveQuality_ = source.GetImageQuality();
+    cachedSlice->status_ = CachedSliceStatus_GeometryLoaded;
+
+    cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
+
+    // re-emit original Layer message to observers
+    BroadcastMessage(message);
+  }
+
+
+  void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message)
+  {
+    // save/replace the slice in cache
+    const Slice& slice = message.GetSlice();
+    std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
+                              boost::lexical_cast<std::string>(slice.GetFrame()));
+
+    LOG(WARNING) << "Image ready: " << sliceKeyId;
+
+    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
+    cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame()));
+    cachedSlice->effectiveQuality_ = message.GetImageQuality();
+    cachedSlice->slice_.reset(message.GetSlice().Clone());
+    cachedSlice->status_ = CachedSliceStatus_ImageLoaded;
+
+    cachedSlices_[sliceKeyId] = cachedSlice;
+
+    // re-emit original Layer message to observers
+    BroadcastMessage(message);
+  }
+
+
+  void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
+  {
+    const DicomSeriesVolumeSlicer& source =
+      dynamic_cast<const DicomSeriesVolumeSlicer&>(message.GetOrigin());
+    
+    const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ?
+    std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
+                              boost::lexical_cast<std::string>(slice.GetFrame()));
+
+    LOG(WARNING) << "Layer ready: " << sliceKeyId;
+
+    // remove the slice from the preloading slices now that it has been fully loaded and it is referenced in the cache
+    if (preloadingInstances_.find(sliceKeyId) != preloadingInstances_.end())
+    {
+      preloadingInstances_.erase(sliceKeyId);
+    }
+
+    // re-emit original Layer message to observers
+    BroadcastMessage(message);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/SmartLoader.h	Tue May 21 14:27:35 2019 +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-2019 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 <map>
+
+#include "Layers/DicomSeriesVolumeSlicer.h"
+#include "../Messages/IObservable.h"
+#include "Toolbox/OrthancApiClient.h"
+
+namespace Deprecated
+{
+  class SliceViewerWidget;
+
+  class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
+  {
+    class CachedSlice;
+
+  protected:
+    typedef std::map<std::string, boost::shared_ptr<SmartLoader::CachedSlice> > CachedSlices;
+    CachedSlices cachedSlices_;
+
+    typedef std::map<std::string, boost::shared_ptr<IVolumeSlicer> > PreloadingInstances;
+    PreloadingInstances preloadingInstances_;
+
+    OrthancStone::SliceImageQuality     imageQuality_;
+    OrthancApiClient&     orthancApiClient_;
+
+  public:
+    SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient);  // TODO: add maxPreloadStorageSizeInBytes
+
+//    void PreloadStudy(const std::string studyId);
+//    void PreloadSeries(const std::string seriesId);
+    void PreloadSlice(const std::string instanceId, unsigned int frame);
+
+    void SetImageQuality(OrthancStone::SliceImageQuality imageQuality) { imageQuality_ = imageQuality; }
+
+    void SetFrameInWidget(SliceViewerWidget& sliceViewer, size_t layerIndex, const std::string& instanceId, unsigned int frame);
+
+    void GetFirstInstanceIdForSeries(std::string& output, const std::string& seriesId);
+
+  private:
+    void OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
+    void OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message);
+    void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message);
+
+  };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/BaseWebService.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,143 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 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 "BaseWebService.h"
+
+#include <Core/OrthancException.h>
+#include "Framework/Messages/IObservable.h"
+#include "Platforms/Generic/IOracleCommand.h"
+#include <boost/shared_ptr.hpp>
+
+namespace Deprecated
+{
+
+
+  class BaseWebService::BaseWebServicePayload : public Orthanc::IDynamicObject
+  {
+  private:
+    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> >   userSuccessHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >     userFailureHandler_;
+    std::auto_ptr< Orthanc::IDynamicObject>                                   userPayload_;
+
+  public:
+    BaseWebServicePayload(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* userSuccessHandler,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* userFailureHandler,
+                          Orthanc::IDynamicObject* userPayload) :
+      userSuccessHandler_(userSuccessHandler),
+      userFailureHandler_(userFailureHandler),
+      userPayload_(userPayload)
+    {
+    }
+
+    void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const
+    {
+      if (userSuccessHandler_.get() != NULL)
+      {
+        // recreate a success message with the user payload
+        IWebService::HttpRequestSuccessMessage successMessage(message.GetUri(),
+                                                              message.GetAnswer(),
+                                                              message.GetAnswerSize(),
+                                                              message.GetAnswerHttpHeaders(),
+                                                              userPayload_.get());
+        userSuccessHandler_->Apply(successMessage);
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+
+    void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const
+    {
+      if (userFailureHandler_.get() != NULL)
+      {
+        // recreate a failure message with the user payload
+        IWebService::HttpRequestErrorMessage failureMessage(message.GetUri(),
+                                                            userPayload_.get());
+
+        userFailureHandler_->Apply(failureMessage);
+      }
+    }
+
+  };
+
+
+  void BaseWebService::GetAsync(const std::string& uri,
+                                const HttpHeaders& headers,
+                                Orthanc::IDynamicObject* payload  /* takes ownership */,
+                                OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                                OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+                                unsigned int timeoutInSeconds)
+  {
+    if (cache_.find(uri) == cache_.end())
+    {
+      GetAsyncInternal(uri, headers,
+                       new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered
+                       new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestSuccessMessage>
+                       (*this, &BaseWebService::CacheAndNotifyHttpSuccess),
+                       new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestErrorMessage>
+                       (*this, &BaseWebService::NotifyHttpError),
+                       timeoutInSeconds);
+    }
+    else
+    {
+      // create a command and "post" it to the Oracle so it is executed and commited "later"
+      NotifyHttpSuccessLater(cache_[uri], payload, successCallback);
+    }
+
+  }
+
+
+
+  void BaseWebService::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
+  {
+    if (message.HasPayload())
+    {
+      dynamic_cast<const BaseWebServicePayload&>(message.GetPayload()).HandleSuccess(message);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+  void BaseWebService::CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
+  {
+    cache_[message.GetUri()] = boost::shared_ptr<CachedHttpRequestSuccessMessage>(new CachedHttpRequestSuccessMessage(message));
+    NotifyHttpSuccess(message);
+  }
+
+  void BaseWebService::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message)
+  {
+    if (message.HasPayload())
+    {
+      dynamic_cast<const BaseWebServicePayload&>(message.GetPayload()).HandleFailure(message);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/BaseWebService.h	Tue May 21 14:27:35 2019 +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-2018 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 "IWebService.h"
+
+#include <string>
+#include <map>
+
+namespace Deprecated
+{
+  // This is an intermediate of IWebService that implements some caching on
+  // the HTTP GET requests
+  class BaseWebService : public IWebService, public OrthancStone::IObserver
+  {
+  public:
+    class CachedHttpRequestSuccessMessage
+    {
+    protected:
+      std::string                    uri_;
+      void*                          answer_;
+      size_t                         answerSize_;
+      IWebService::HttpHeaders       answerHeaders_;
+
+    public:
+      CachedHttpRequestSuccessMessage(const IWebService::HttpRequestSuccessMessage& message) :
+        uri_(message.GetUri()),
+        answerSize_(message.GetAnswerSize()),
+        answerHeaders_(message.GetAnswerHttpHeaders())
+      {
+        answer_ =  malloc(answerSize_);
+        memcpy(answer_, message.GetAnswer(), answerSize_);
+      }
+
+      ~CachedHttpRequestSuccessMessage()
+      {
+        free(answer_);
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const void* GetAnswer() const
+      {
+        return answer_;
+      }
+
+      size_t GetAnswerSize() const
+      {
+        return answerSize_;
+      }
+
+      const IWebService::HttpHeaders&  GetAnswerHttpHeaders() const
+      {
+        return answerHeaders_;
+      }
+
+    };
+  protected:
+    class BaseWebServicePayload;
+
+    bool          cacheEnabled_;
+    std::map<std::string, boost::shared_ptr<CachedHttpRequestSuccessMessage> > cache_;  // TODO: this is currently an infinite cache !
+
+  public:
+
+    BaseWebService(OrthancStone::MessageBroker& broker) :
+      IWebService(broker),
+      IObserver(broker),
+      cacheEnabled_(true)
+    {
+    }
+
+    virtual ~BaseWebService()
+    {
+    }
+
+    virtual void EnableCache(bool enable)
+    {
+      cacheEnabled_ = enable;
+    }
+
+    virtual void GetAsync(const std::string& uri,
+                          const HttpHeaders& headers,
+                          Orthanc::IDynamicObject* payload  /* takes ownership */,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                          unsigned int timeoutInSeconds = 60);
+
+  protected:
+    virtual void GetAsyncInternal(const std::string& uri,
+                          const HttpHeaders& headers,
+                          Orthanc::IDynamicObject* payload  /* takes ownership */,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                          unsigned int timeoutInSeconds = 60) = 0;
+
+    virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
+                                        Orthanc::IDynamicObject* payload, // takes ownership
+                                        OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback) = 0;
+
+  private:
+    void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
+
+    void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message);
+
+    void CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
+
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/DicomFrameConverter.cpp	Tue May 21 14:27:35 2019 +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-2019 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 "DicomFrameConverter.h"
+
+#include "../../Toolbox/LinearAlgebra.h"
+
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
+#include <Core/OrthancException.h>
+#include <Core/Toolbox.h>
+
+namespace Deprecated
+{
+  static const Orthanc::DicomTag IMAGE_TAGS[] =
+  {
+    Orthanc::DICOM_TAG_BITS_STORED,
+    Orthanc::DICOM_TAG_DOSE_GRID_SCALING,
+    Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION,
+    Orthanc::DICOM_TAG_PIXEL_REPRESENTATION,
+    Orthanc::DICOM_TAG_RESCALE_INTERCEPT,
+    Orthanc::DICOM_TAG_RESCALE_SLOPE,
+    Orthanc::DICOM_TAG_WINDOW_CENTER,
+    Orthanc::DICOM_TAG_WINDOW_WIDTH
+  };
+
+  
+  void DicomFrameConverter::SetDefaultParameters()
+  {
+    isSigned_ = true;
+    isColor_ = false;
+    hasRescale_ = false;
+    rescaleIntercept_ = 0;
+    rescaleSlope_ = 1;
+    hasDefaultWindow_ = false;
+    defaultWindowCenter_ = 128;
+    defaultWindowWidth_ = 256;
+    expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+  }
+
+
+  void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom)
+  {
+    SetDefaultParameters();
+
+    OrthancStone::Vector c, w;
+    if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
+        OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
+        c.size() > 0 && 
+        w.size() > 0)
+    {
+      hasDefaultWindow_ = true;
+      defaultWindowCenter_ = static_cast<float>(c[0]);
+      defaultWindowWidth_ = static_cast<float>(w[0]);
+    }
+
+    int32_t tmp;
+    if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION))
+    {
+      // Type 1 tag, must be present
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    isSigned_ = (tmp == 1);
+
+    double doseGridScaling;
+    bool isRTDose = false;
+    
+    if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) &&
+        dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE))
+    {
+      hasRescale_ = true;
+    }
+    else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING))
+    {
+      // This is for RT-DOSE
+      hasRescale_ = true;
+      isRTDose = true;
+      rescaleIntercept_ = 0;
+      rescaleSlope_ = doseGridScaling;
+
+      if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_BITS_STORED))
+      {
+        // Type 1 tag, must be present
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+      }
+
+      switch (tmp)
+      {
+        case 16:
+          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+          break;
+
+        case 32:
+          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      }
+    }
+
+    std::string photometric;
+    if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false))
+    {
+      photometric = Orthanc::Toolbox::StripSpaces(photometric);
+    }
+    else
+    {
+      // Type 1 tag, must be present
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
+    }
+
+    photometric_ = Orthanc::StringToPhotometricInterpretation(photometric.c_str());
+    
+    isColor_ = (photometric != "MONOCHROME1" &&
+                photometric != "MONOCHROME2");
+
+    // TODO Add more checks, e.g. on the number of bytes per value
+    // (cf. DicomImageInformation.h in Orthanc)
+
+    if (!isRTDose)
+    {
+      if (isColor_)
+      {
+        expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
+      }
+      else if (isSigned_)
+      {
+        expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
+      }
+      else
+      {
+        expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
+      }
+    }
+  }
+
+  
+  void DicomFrameConverter::ReadParameters(const OrthancPlugins::IDicomDataset& dicom)
+  {
+    Orthanc::DicomMap converted;
+
+    for (size_t i = 0; i < sizeof(IMAGE_TAGS) / sizeof(Orthanc::DicomTag); i++)
+    {
+      OrthancPlugins::DicomTag tag(IMAGE_TAGS[i].GetGroup(), IMAGE_TAGS[i].GetElement());
+    
+      std::string value;
+      if (dicom.GetStringValue(value, tag))
+      {
+        converted.SetValue(IMAGE_TAGS[i], value, false);
+      }
+    }
+
+    ReadParameters(converted);
+  }
+    
+
+  void DicomFrameConverter::ConvertFrameInplace(std::auto_ptr<Orthanc::ImageAccessor>& source) const
+  {
+    assert(sizeof(float) == 4);
+
+    if (source.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    if (source->GetFormat() == GetExpectedPixelFormat() &&
+        source->GetFormat() == Orthanc::PixelFormat_RGB24)
+    {
+      // No conversion has to be done, check out (*)
+      return;
+    }
+    else
+    {
+      source.reset(ConvertFrame(*source));
+    }
+  }
+
+
+  Orthanc::ImageAccessor* DicomFrameConverter::ConvertFrame(const Orthanc::ImageAccessor& source) const
+  {
+    assert(sizeof(float) == 4);
+
+    Orthanc::PixelFormat sourceFormat = source.GetFormat();
+
+    if (sourceFormat != GetExpectedPixelFormat())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+
+    if (sourceFormat == Orthanc::PixelFormat_RGB24)
+    {
+      // This is the case of a color image. No conversion has to be done (*)
+      std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_RGB24, 
+                                                                 source.GetWidth(), 
+                                                                 source.GetHeight(),
+                                                                 false));
+      Orthanc::ImageProcessing::Copy(*converted, source);
+      return converted.release();
+    }
+    else
+    {
+      assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 ||
+             sourceFormat == Orthanc::PixelFormat_Grayscale32 ||
+             sourceFormat == Orthanc::PixelFormat_SignedGrayscale16);
+
+      // This is the case of a grayscale frame. Convert it to Float32.
+      std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
+                                                                 source.GetWidth(), 
+                                                                 source.GetHeight(),
+                                                                 false));
+      Orthanc::ImageProcessing::Convert(*converted, source);
+
+      // Correct rescale slope/intercept if need be
+      ApplyRescale(*converted, sourceFormat != Orthanc::PixelFormat_Grayscale32);
+      
+      return converted.release();
+    }
+  }
+
+
+  void DicomFrameConverter::ApplyRescale(Orthanc::ImageAccessor& image,
+                                         bool useDouble) const
+  {
+    if (image.GetFormat() != Orthanc::PixelFormat_Float32)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+    }
+    
+    if (hasRescale_)
+    {
+      for (unsigned int y = 0; y < image.GetHeight(); y++)
+      {
+        float* p = reinterpret_cast<float*>(image.GetRow(y));
+
+        if (useDouble)
+        {
+          // Slower, accurate implementation using double
+          for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+          {
+            double value = static_cast<double>(*p);
+            *p = static_cast<float>(value * rescaleSlope_ + rescaleIntercept_);
+          }
+        }
+        else
+        {
+          // Fast, approximate implementation using float
+          for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
+          {
+            *p = (*p) * static_cast<float>(rescaleSlope_) + static_cast<float>(rescaleIntercept_);
+          }
+        }
+      }
+    }
+  }
+
+  
+  double DicomFrameConverter::Apply(double x) const
+  {
+    return x * rescaleSlope_ + rescaleIntercept_;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/DicomFrameConverter.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,169 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <Plugins/Samples/Common/IDicomDataset.h>
+#include <Core/DicomFormat/DicomMap.h>
+#include <Core/Images/ImageAccessor.h>
+
+#include <memory>
+
+namespace Deprecated
+{
+  /**
+   * This class is responsible for converting the pixel format of a
+   * DICOM frame coming from Orthanc, into a pixel format that is
+   * suitable for Stone, given the relevant DICOM tags:
+   * - Color frames will stay in the RGB24 format.
+   * - Grayscale frames will be converted to the Float32 format.
+   **/
+  class DicomFrameConverter
+  {
+  private:
+    bool    isSigned_;
+    bool    isColor_;
+    bool    hasRescale_;
+    double  rescaleIntercept_;
+    double  rescaleSlope_;
+    bool    hasDefaultWindow_;
+    double  defaultWindowCenter_;
+    double  defaultWindowWidth_;
+    
+    Orthanc::PhotometricInterpretation  photometric_;
+    Orthanc::PixelFormat                expectedPixelFormat_;
+
+    void SetDefaultParameters();
+
+  public:
+    DicomFrameConverter()
+    {
+      SetDefaultParameters();
+    }
+
+    ~DicomFrameConverter()
+    {
+      // TODO: check whether this dtor is called or not
+      // An MSVC warning explains that declaring an
+      // std::auto_ptr with a forward-declared type
+      // prevents its dtor from being called. Does not
+      // seem an issue here (only POD types inside), but
+      // definitely something to keep an eye on.
+      (void)0;
+    }
+
+    // AM: this is required to serialize/deserialize it
+    DicomFrameConverter(
+        bool isSigned,
+        bool isColor,
+        bool hasRescale,
+        double rescaleIntercept,
+        double rescaleSlope,
+        bool hasDefaultWindow,
+        double defaultWindowCenter,
+        double defaultWindowWidth,
+        Orthanc::PhotometricInterpretation photometric,
+        Orthanc::PixelFormat expectedPixelFormat
+        ):
+      isSigned_(isSigned),
+      isColor_(isColor),
+      hasRescale_(hasRescale),
+      rescaleIntercept_(rescaleIntercept),
+      rescaleSlope_(rescaleSlope),
+      hasDefaultWindow_(hasDefaultWindow),
+      defaultWindowCenter_(defaultWindowCenter),
+      defaultWindowWidth_(defaultWindowWidth),
+      photometric_(photometric),
+      expectedPixelFormat_(expectedPixelFormat)
+    {}
+
+    void GetParameters(bool& isSigned,
+                       bool& isColor,
+                       bool& hasRescale,
+                       double& rescaleIntercept,
+                       double& rescaleSlope,
+                       bool& hasDefaultWindow,
+                       double& defaultWindowCenter,
+                       double& defaultWindowWidth,
+                       Orthanc::PhotometricInterpretation& photometric,
+                       Orthanc::PixelFormat& expectedPixelFormat) const
+    {
+      isSigned = isSigned_;
+      isColor = isColor_;
+      hasRescale = hasRescale_;
+      rescaleIntercept = rescaleIntercept_;
+      rescaleSlope = rescaleSlope_;
+      hasDefaultWindow = hasDefaultWindow_;
+      defaultWindowCenter = defaultWindowCenter_;
+      defaultWindowWidth = defaultWindowWidth_;
+      photometric = photometric_;
+      expectedPixelFormat = expectedPixelFormat_;
+    }
+
+    Orthanc::PixelFormat GetExpectedPixelFormat() const
+    {
+      return expectedPixelFormat_;
+    }
+
+    Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
+    {
+      return photometric_;
+    }
+
+    void ReadParameters(const Orthanc::DicomMap& dicom);
+
+    void ReadParameters(const OrthancPlugins::IDicomDataset& dicom);
+
+    bool HasDefaultWindow() const
+    {
+      return hasDefaultWindow_;
+    }
+    
+    double GetDefaultWindowCenter() const
+    {
+      return defaultWindowCenter_;
+    }
+    
+    double GetDefaultWindowWidth() const
+    {
+      return defaultWindowWidth_;
+    }
+
+    double GetRescaleIntercept() const
+    {
+      return rescaleIntercept_;
+    }
+
+    double GetRescaleSlope() const
+    {
+      return rescaleSlope_;
+    }
+
+    void ConvertFrameInplace(std::auto_ptr<Orthanc::ImageAccessor>& source) const;
+
+    Orthanc::ImageAccessor* ConvertFrame(const Orthanc::ImageAccessor& source) const;
+
+    void ApplyRescale(Orthanc::ImageAccessor& image,
+                      bool useDouble) const;
+
+    double Apply(double x) const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/DownloadStack.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,196 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "DownloadStack.h"
+
+#include <Core/OrthancException.h>
+
+#include <cassert>
+
+namespace Deprecated
+{
+  bool DownloadStack::CheckInvariants() const
+  {
+    std::vector<bool> dequeued(nodes_.size(), true);
+
+    int i = firstNode_;
+    while (i != NIL)
+    {
+      const Node& node = nodes_[i];
+
+      dequeued[i] = false;
+
+      if (node.next_ != NIL &&
+          nodes_[node.next_].prev_ != i)
+      {
+        return false;
+      }
+
+      if (node.prev_ != NIL &&
+          nodes_[node.prev_].next_ != i)
+      {
+        return false;
+      }
+
+      i = nodes_[i].next_;
+    }
+
+    for (size_t i = 0; i < nodes_.size(); i++)
+    {
+      if (nodes_[i].dequeued_ != dequeued[i])
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+
+  DownloadStack::DownloadStack(unsigned int size)
+  {
+    nodes_.resize(size);
+
+    if (size == 0)
+    {
+      firstNode_ = NIL;
+    }
+    else
+    {
+      for (size_t i = 0; i < size; i++)
+      {
+        nodes_[i].prev_ = static_cast<int>(i - 1);
+        nodes_[i].next_ = static_cast<int>(i + 1);
+        nodes_[i].dequeued_ = false;
+      }
+
+      nodes_.front().prev_ = NIL;
+      nodes_.back().next_ = NIL;
+      firstNode_ = 0;
+    }
+
+    assert(CheckInvariants());
+  }
+
+
+  DownloadStack::~DownloadStack()
+  {
+    assert(CheckInvariants());    
+  }
+
+
+  bool DownloadStack::Pop(unsigned int& value)
+  {
+    assert(CheckInvariants());
+
+    if (firstNode_ == NIL)
+    {
+      for (size_t i = 0; i < nodes_.size(); i++)
+      {
+        assert(nodes_[i].dequeued_);
+      }
+
+      return false;
+    }
+    else
+    {
+      assert(firstNode_ >= 0 && firstNode_ < static_cast<int>(nodes_.size()));
+      value = firstNode_;
+
+      Node& node = nodes_[firstNode_];
+      assert(node.prev_ == NIL);
+      assert(!node.dequeued_);
+
+      node.dequeued_ = true;
+      firstNode_ = node.next_;
+
+      if (firstNode_ != NIL)
+      {
+        nodes_[firstNode_].prev_ = NIL;
+      }
+
+      return true;
+    }
+  }
+
+
+  void DownloadStack::SetTopNodeInternal(unsigned int value)
+  {
+    assert(CheckInvariants());
+
+    Node& node = nodes_[value];
+
+    if (node.dequeued_)
+    {
+      // This node has already been processed by the download thread, nothing to do
+      return;
+    }
+
+    // Remove the node from the list
+    if (node.prev_ == NIL)
+    {
+      assert(firstNode_ == static_cast<int>(value));
+      
+      // This is already the top node in the list, nothing to do
+      return;
+    }
+
+    nodes_[node.prev_].next_ = node.next_;
+
+    if (node.next_ != NIL)
+    {
+      nodes_[node.next_].prev_ = node.prev_;
+    }
+
+    // Add back the node at the top of the list
+    assert(firstNode_ != NIL);
+
+    Node& old = nodes_[firstNode_];
+    assert(old.prev_ == NIL);
+    assert(!old.dequeued_);
+    node.prev_ = NIL;
+    node.next_ = firstNode_;
+    old.prev_ = value;
+
+    firstNode_ = value;
+  }
+
+  
+  void DownloadStack::SetTopNode(unsigned int value)
+  {
+    if (value >= nodes_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    SetTopNodeInternal(value);
+  }
+
+
+  void DownloadStack::SetTopNodePermissive(int value)
+  {
+    if (value >= 0 &&
+        value < static_cast<int>(nodes_.size()))
+    {
+      SetTopNodeInternal(value);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/DownloadStack.h	Tue May 21 14:27:35 2019 +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-2019 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 <vector>
+#include <boost/noncopyable.hpp>
+
+namespace Deprecated
+{
+  class DownloadStack : public boost::noncopyable
+  {
+  private:
+    static const int NIL = -1;
+
+    // This is a doubly-linked list
+    struct Node
+    {
+      int   next_;
+      int   prev_;
+      bool  dequeued_;
+    };
+
+    std::vector<Node>   nodes_;
+    int                 firstNode_;
+
+    bool CheckInvariants() const;
+
+    void SetTopNodeInternal(unsigned int value);  
+
+  public:
+    DownloadStack(unsigned int size);
+
+    ~DownloadStack();
+
+    bool Pop(unsigned int& value);
+
+    void SetTopNode(unsigned int value);  
+
+    void SetTopNodePermissive(int value);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h	Tue May 21 14:27:35 2019 +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-2018 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 "../../Messages/IObserver.h"
+#include "../../Messages/ICallable.h"
+
+#include <Core/IDynamicObject.h>
+#include <Core/Logging.h>
+
+#include <string>
+#include <map>
+
+namespace Deprecated
+{
+  // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript).
+  class IDelayedCallExecutor : public boost::noncopyable
+  {
+  protected:
+    OrthancStone::MessageBroker& broker_;
+    
+  public:
+    ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage);
+
+    IDelayedCallExecutor(OrthancStone::MessageBroker& broker) :
+      broker_(broker)
+    {
+    }
+
+    
+    virtual ~IDelayedCallExecutor()
+    {
+    }
+
+    
+    virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
+                          unsigned int timeoutInMs = 1000) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/IWebService.cpp	Tue May 21 14:27:35 2019 +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-2019 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 "IWebService.h"
+
+#include <Core/OrthancException.h>
+
+
+namespace Deprecated
+{
+  const Orthanc::IDynamicObject&
+  IWebService::HttpRequestSuccessMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+    
+
+  const Orthanc::IDynamicObject&
+  IWebService::HttpRequestErrorMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/IWebService.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,166 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Messages/IObserver.h"
+#include "../../Messages/ICallable.h"
+
+#include <Core/IDynamicObject.h>
+#include <Core/Logging.h>
+
+#include <string>
+#include <map>
+
+namespace Deprecated
+{
+  // The IWebService performs HTTP requests.
+  // Since applications can run in native or WASM environment and, since
+  // in a WASM environment, the WebService is asynchronous, the IWebservice
+  // also implements an asynchronous interface: you must schedule a request
+  // and you'll be notified when the response/error is ready.
+  class IWebService : public boost::noncopyable
+  {
+  protected:
+    OrthancStone::MessageBroker& broker_;
+    
+  public:
+    typedef std::map<std::string, std::string> HttpHeaders;
+
+    class HttpRequestSuccessMessage : public OrthancStone::IMessage
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
+    private:
+      const std::string&             uri_;
+      const void*                    answer_;
+      size_t                         answerSize_;
+      const HttpHeaders&             answerHeaders_;
+      const Orthanc::IDynamicObject* payload_;
+
+    public:
+      HttpRequestSuccessMessage(const std::string& uri,
+                                const void* answer,
+                                size_t answerSize,
+                                const HttpHeaders& answerHeaders,
+                                const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        answer_(answer),
+        answerSize_(answerSize),
+        answerHeaders_(answerHeaders),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const void* GetAnswer() const
+      {
+        return answer_;
+      }
+
+      size_t GetAnswerSize() const
+      {
+        return answerSize_;
+      }
+
+      const HttpHeaders&  GetAnswerHttpHeaders() const
+      {
+        return answerHeaders_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+    };
+    
+
+    class HttpRequestErrorMessage : public OrthancStone::IMessage
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
+    private:
+      const std::string&              uri_;
+      const Orthanc::IDynamicObject*  payload_;
+
+    public:
+      HttpRequestErrorMessage(const std::string& uri,
+                              const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+    };
+
+
+    IWebService(OrthancStone::MessageBroker& broker) :
+      broker_(broker)
+    {
+    }
+
+    
+    virtual ~IWebService()
+    {
+    }
+
+    virtual void EnableCache(bool enable) = 0;
+    
+    virtual void GetAsync(const std::string& uri,
+                          const HttpHeaders& headers,
+                          Orthanc::IDynamicObject* payload  /* takes ownership */,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                          unsigned int timeoutInSeconds = 60) = 0;
+
+    virtual void PostAsync(const std::string& uri,
+                           const HttpHeaders& headers,
+                           const std::string& body,
+                           Orthanc::IDynamicObject* payload  /* takes ownership */,
+                           OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                           unsigned int timeoutInSeconds = 60) = 0;
+
+    virtual void DeleteAsync(const std::string& uri,
+                             const HttpHeaders& headers,
+                             Orthanc::IDynamicObject* payload  /* takes ownership */,
+                             OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+                             OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                             unsigned int timeoutInSeconds = 60) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/OrthancApiClient.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,336 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "OrthancApiClient.h"
+
+#include "../../Toolbox/MessagingToolbox.h"
+
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  const Orthanc::IDynamicObject& OrthancApiClient::BinaryResponseReadyMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  const Orthanc::IDynamicObject& OrthancApiClient::EmptyResponseReadyMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject
+  {
+  private:
+    std::auto_ptr< OrthancStone::MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
+    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
+    std::auto_ptr< Orthanc::IDynamicObject >                               userPayload_;
+
+    void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const
+    {
+      if (failureHandler_.get() != NULL)
+      {
+        failureHandler_->Apply(IWebService::HttpRequestErrorMessage
+                               (message.GetUri(), userPayload_.get()));
+      }
+    }
+    
+  public:
+    WebServicePayload(OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
+                      Orthanc::IDynamicObject* userPayload) :
+      emptyHandler_(handler),
+      failureHandler_(failureHandler),
+      userPayload_(userPayload)
+    {
+      if (handler == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+    }
+
+    WebServicePayload(OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
+                      Orthanc::IDynamicObject* userPayload) :
+      binaryHandler_(handler),
+      failureHandler_(failureHandler),
+      userPayload_(userPayload)
+    {
+      if (handler == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+    }
+
+    WebServicePayload(OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
+                      Orthanc::IDynamicObject* userPayload) :
+      jsonHandler_(handler),
+      failureHandler_(failureHandler),
+      userPayload_(userPayload)
+    {
+      if (handler == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+    }
+
+    void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const
+    {
+      if (emptyHandler_.get() != NULL)
+      {
+        emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage
+                             (message.GetUri(), userPayload_.get()));
+      }
+      else if (binaryHandler_.get() != NULL)
+      {
+        binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage
+                              (message.GetUri(), message.GetAnswer(),
+                               message.GetAnswerSize(), userPayload_.get()));
+      }
+      else if (jsonHandler_.get() != NULL)
+      {
+        Json::Value response;
+        if (OrthancStone::MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
+        {
+          jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage
+                              (message.GetUri(), response, userPayload_.get()));
+        }
+        else
+        {
+          NotifyConversionError(message);
+        }
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+
+    void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const
+    {
+      if (failureHandler_.get() != NULL)
+      {
+        failureHandler_->Apply(IWebService::HttpRequestErrorMessage
+                               (message.GetUri(), userPayload_.get()));
+      }
+    }
+  };
+
+
+  OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker,
+                                     IWebService& web,
+                                     const std::string& baseUrl) :
+    IObservable(broker),
+    IObserver(broker),
+    web_(web),
+    baseUrl_(baseUrl)
+  {
+  }
+
+
+  void OrthancApiClient::GetJsonAsync(
+      const std::string& uri,
+      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload)
+  {
+    IWebService::HttpHeaders emptyHeaders;
+    web_.GetAsync(baseUrl_ + uri,
+                  emptyHeaders,
+                  new WebServicePayload(successCallback, failureCallback, payload),
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                  (*this, &OrthancApiClient::NotifyHttpSuccess),
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                  (*this, &OrthancApiClient::NotifyHttpError));
+  }
+
+
+  void OrthancApiClient::GetBinaryAsync(
+      const std::string& uri,
+      const std::string& contentType,
+      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload)
+  {
+    IWebService::HttpHeaders headers;
+    headers["Accept"] = contentType;
+    GetBinaryAsync(uri, headers, successCallback, failureCallback, payload);
+  }
+
+  void OrthancApiClient::GetBinaryAsync(
+      const std::string& uri,
+      const IWebService::HttpHeaders& headers,
+      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload)
+  {
+    // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str());
+
+    web_.GetAsync(baseUrl_ + uri, headers,
+                  new WebServicePayload(successCallback, failureCallback, payload),
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                  (*this, &OrthancApiClient::NotifyHttpSuccess),
+                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                  (*this, &OrthancApiClient::NotifyHttpError));
+  }
+
+  
+  void OrthancApiClient::PostBinaryAsyncExpectJson(
+      const std::string& uri,
+      const std::string& body,
+      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload)
+  {
+    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
+                   new WebServicePayload(successCallback, failureCallback, payload),
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                   (*this, &OrthancApiClient::NotifyHttpSuccess),
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                   (*this, &OrthancApiClient::NotifyHttpError));
+
+  }
+
+  void OrthancApiClient::PostBinaryAsync(
+      const std::string& uri,
+      const std::string& body)
+  {
+    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, NULL, NULL, NULL);
+  }
+
+  void OrthancApiClient::PostBinaryAsync(
+      const std::string& uri,
+      const std::string& body,
+      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload   /* takes ownership */)
+  {
+    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
+                   new WebServicePayload(successCallback, failureCallback, payload),
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                   (*this, &OrthancApiClient::NotifyHttpSuccess),
+                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                   (*this, &OrthancApiClient::NotifyHttpError));
+  }
+
+  void OrthancApiClient::PostJsonAsyncExpectJson(
+      const std::string& uri,
+      const Json::Value& data,
+      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload)
+  {
+    std::string body;
+    OrthancStone::MessagingToolbox::JsonToString(body, data);
+    return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload);
+  }
+
+  void OrthancApiClient::PostJsonAsync(
+      const std::string& uri,
+      const Json::Value& data)
+  {
+    std::string body;
+    OrthancStone::MessagingToolbox::JsonToString(body, data);
+    return PostBinaryAsync(uri, body);
+  }
+
+  void OrthancApiClient::PostJsonAsync(
+      const std::string& uri,
+      const Json::Value& data,
+      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload   /* takes ownership */)
+  {
+    std::string body;
+    OrthancStone::MessagingToolbox::JsonToString(body, data);
+    return PostBinaryAsync(uri, body, successCallback, failureCallback, payload);
+  }
+
+  void OrthancApiClient::DeleteAsync(
+      const std::string& uri,
+      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
+      Orthanc::IDynamicObject* payload)
+  {
+    web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(),
+                     new WebServicePayload(successCallback, failureCallback, payload),
+                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
+                     (*this, &OrthancApiClient::NotifyHttpSuccess),
+                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
+                     (*this, &OrthancApiClient::NotifyHttpError));
+  }
+
+
+  void OrthancApiClient::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
+  {
+    if (message.HasPayload())
+    {
+      dynamic_cast<const WebServicePayload&>(message.GetPayload()).HandleSuccess(message);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+  void OrthancApiClient::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message)
+  {
+    if (message.HasPayload())
+    {
+      dynamic_cast<const WebServicePayload&>(message.GetPayload()).HandleFailure(message);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/OrthancApiClient.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,243 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <json/json.h>
+
+#include "IWebService.h"
+#include "../../Messages/IObservable.h"
+#include "../../Messages/Promise.h"
+
+namespace Deprecated
+{
+  class OrthancApiClient :
+      public OrthancStone::IObservable,
+      public OrthancStone::IObserver
+  {
+  public:
+    class JsonResponseReadyMessage : public OrthancStone::IMessage
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
+    private:
+      const std::string&              uri_;
+      const Json::Value&              json_;
+      const Orthanc::IDynamicObject*  payload_;
+
+    public:
+      JsonResponseReadyMessage(const std::string& uri,
+                               const Json::Value& json,
+                               const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        json_(json),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const Json::Value& GetJson() const
+      {
+        return json_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+    };
+    
+
+    class BinaryResponseReadyMessage : public OrthancStone::IMessage
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
+    private:
+      const std::string&              uri_;
+      const void*                     answer_;
+      size_t                          answerSize_;
+      const Orthanc::IDynamicObject*  payload_;
+
+    public:
+      BinaryResponseReadyMessage(const std::string& uri,
+                                 const void* answer,
+                                 size_t answerSize,
+                                 const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        answer_(answer),
+        answerSize_(answerSize),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const void* GetAnswer() const
+      {
+        return answer_;
+      }
+
+      size_t GetAnswerSize() const
+      {
+        return answerSize_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+    };
+
+
+    class EmptyResponseReadyMessage : public OrthancStone::IMessage
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+
+    private:
+      const std::string&              uri_;
+      const Orthanc::IDynamicObject*  payload_;
+
+    public:
+      EmptyResponseReadyMessage(const std::string& uri,
+                                const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+    };
+
+    
+
+  private:
+    class WebServicePayload;
+
+  protected:
+    IWebService&  web_;
+    std::string   baseUrl_;
+
+  public:
+    OrthancApiClient(OrthancStone::MessageBroker& broker,
+                     IWebService& web,
+                     const std::string& baseUrl);
+    
+    virtual ~OrthancApiClient()
+    {
+    }
+
+    const std::string& GetBaseUrl() const {return baseUrl_;}
+
+    // schedule a GET request expecting a JSON response.
+    void GetJsonAsync(const std::string& uri,
+                      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                      Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    // schedule a GET request expecting a binary response.
+    void GetBinaryAsync(const std::string& uri,
+                        const std::string& contentType,
+                        OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    // schedule a GET request expecting a binary response.
+    void GetBinaryAsync(const std::string& uri,
+                        const IWebService::HttpHeaders& headers,
+                        OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
+                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    // schedule a POST request expecting a JSON response.
+    void PostBinaryAsyncExpectJson(const std::string& uri,
+                                   const std::string& body,
+                                   OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+                                   OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                                   Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    // schedule a POST request expecting a JSON response.
+    void PostJsonAsyncExpectJson(const std::string& uri,
+                                 const Json::Value& data,
+                                 OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
+                                 OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                                 Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    // schedule a POST request and don't mind the response.
+    void PostJsonAsync(const std::string& uri,
+                       const Json::Value& data);
+
+    // schedule a POST request and don't expect any response.
+    void PostJsonAsync(const std::string& uri,
+                       const Json::Value& data,
+                       OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+                       OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                       Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+
+    // schedule a POST request and don't mind the response.
+    void PostBinaryAsync(const std::string& uri,
+                         const std::string& body);
+
+    // schedule a POST request and don't expect any response.
+    void PostBinaryAsync(const std::string& uri,
+                         const std::string& body,
+                         OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+                         OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                         Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    // schedule a DELETE request expecting an empty response.
+    void DeleteAsync(const std::string& uri,
+                     OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
+                     OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
+                     Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
+
+    void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
+
+    void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message);
+
+  private:
+    void HandleFromCache(const std::string& uri,
+                         const IWebService::HttpHeaders& headers,
+                         Orthanc::IDynamicObject* payload /* takes ownership */);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,904 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "OrthancSlicesLoader.h"
+
+#include "../../Toolbox/MessagingToolbox.h"
+
+#include <Core/Compression/GzipCompressor.h>
+#include <Core/Endianness.h>
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
+#include <Core/Images/JpegReader.h>
+#include <Core/Images/PngReader.h>
+#include <Core/Images/PamReader.h>
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <Core/Toolbox.h>
+#include <Plugins/Samples/Common/FullOrthancDataset.h>
+
+#include <boost/lexical_cast.hpp>
+
+
+
+/**
+ * TODO This is a SLOW implementation of base64 decoding, because
+ * "Orthanc::Toolbox::DecodeBase64()" does not work properly with
+ * WASM. UNDERSTAND WHY.
+ * https://stackoverflow.com/a/34571089/881731
+ **/
+static std::string base64_decode(const std::string &in)
+{
+  std::string out;
+  
+  std::vector<int> T(256,-1);
+  for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
+  
+  int val=0, valb=-8;
+  for (size_t i = 0; i < in.size(); i++) {
+    unsigned char c = in[i];
+    if (T[c] == -1) break;
+    val = (val<<6) + T[c];
+    valb += 6;
+    if (valb>=0) {
+      out.push_back(char((val>>valb)&0xFF));
+      valb-=8;
+    }
+  }
+  return out;
+}
+
+
+
+namespace Deprecated
+{
+  class OrthancSlicesLoader::Operation : public Orthanc::IDynamicObject
+  {
+  private:
+    Mode               mode_;
+    unsigned int       frame_;
+    unsigned int       sliceIndex_;
+    const Slice*       slice_;
+    std::string        instanceId_;
+    OrthancStone::SliceImageQuality  quality_;
+
+    Operation(Mode mode) :
+      mode_(mode)
+    {
+    }
+
+  public:
+    Mode GetMode() const
+    {
+      return mode_;
+    }
+
+    OrthancStone::SliceImageQuality GetQuality() const
+    {
+      assert(mode_ == Mode_LoadImage ||
+             mode_ == Mode_LoadRawImage);
+      return quality_;
+    }
+
+    unsigned int GetSliceIndex() const
+    {
+      assert(mode_ == Mode_LoadImage ||
+             mode_ == Mode_LoadRawImage);
+      return sliceIndex_;
+    }
+
+    const Slice& GetSlice() const
+    {
+      assert(mode_ == Mode_LoadImage ||
+             mode_ == Mode_LoadRawImage);
+      assert(slice_ != NULL);
+      return *slice_;
+    }
+
+    unsigned int GetFrame() const
+    {
+      assert(mode_ == Mode_FrameGeometry);
+      return frame_;
+    }
+
+    const std::string& GetInstanceId() const
+    {
+      assert(mode_ == Mode_FrameGeometry ||
+             mode_ == Mode_InstanceGeometry);
+      return instanceId_;
+    }
+
+    static Operation* DownloadInstanceGeometry(const std::string& instanceId)
+    {
+      std::auto_ptr<Operation> operation(new Operation(Mode_InstanceGeometry));
+      operation->instanceId_ = instanceId;
+      return operation.release();
+    }
+
+    static Operation* DownloadFrameGeometry(const std::string& instanceId,
+                                            unsigned int frame)
+    {
+      std::auto_ptr<Operation> operation(new Operation(Mode_FrameGeometry));
+      operation->instanceId_ = instanceId;
+      operation->frame_ = frame;
+      return operation.release();
+    }
+
+    static Operation* DownloadSliceImage(unsigned int  sliceIndex,
+                                         const Slice&  slice,
+                                         OrthancStone::SliceImageQuality quality)
+    {
+      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadImage));
+      tmp->sliceIndex_ = sliceIndex;
+      tmp->slice_ = &slice;
+      tmp->quality_ = quality;
+      return tmp.release();
+    }
+
+    static Operation* DownloadSliceRawImage(unsigned int  sliceIndex,
+                                            const Slice&  slice)
+    {
+      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadRawImage));
+      tmp->sliceIndex_ = sliceIndex;
+      tmp->slice_ = &slice;
+      tmp->quality_ = OrthancStone::SliceImageQuality_InternalRaw;
+      return tmp.release();
+    }
+
+    static Operation* DownloadDicomFile(const Slice&  slice)
+    {
+      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadDicomFile));
+      tmp->slice_ = &slice;
+      return tmp.release();
+    }
+
+  };
+
+  void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation,
+                                                    const Orthanc::ImageAccessor& image)
+  {
+    OrthancSlicesLoader::SliceImageReadyMessage msg
+      (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality());
+    BroadcastMessage(msg);
+  }
+  
+  
+  void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation)
+  {
+    OrthancSlicesLoader::SliceImageErrorMessage msg
+      (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality());
+    BroadcastMessage(msg);
+  }
+  
+  
+  void OrthancSlicesLoader::SortAndFinalizeSlices()
+  {
+    bool ok = slices_.Sort();
+    
+    state_ = State_GeometryReady;
+    
+    if (ok)
+    {
+      LOG(INFO) << "Loaded a series with " << slices_.GetSlicesCount() << " slice(s)";
+      BroadcastMessage(SliceGeometryReadyMessage(*this));
+    }
+    else
+    {
+      LOG(ERROR) << "This series is empty";
+      BroadcastMessage(SliceGeometryErrorMessage(*this));
+    }
+  }
+  
+  void OrthancSlicesLoader::OnGeometryError(const IWebService::HttpRequestErrorMessage& message)
+  {
+    BroadcastMessage(SliceGeometryErrorMessage(*this));
+    state_ = State_Error;
+  }
+
+  void OrthancSlicesLoader::OnSliceImageError(const IWebService::HttpRequestErrorMessage& message)
+  {
+    NotifySliceImageError(dynamic_cast<const Operation&>(message.GetPayload()));
+    state_ = State_Error;
+  }
+
+  void OrthancSlicesLoader::ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& series = message.GetJson();
+    Json::Value::Members instances = series.getMemberNames();
+    
+    slices_.Reserve(instances.size());
+    
+    for (size_t i = 0; i < instances.size(); i++)
+    {
+      OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]);
+      
+      Orthanc::DicomMap dicom;
+      OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
+      
+      unsigned int frames;
+      if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
+      {
+        frames = 1;
+      }
+      
+      for (unsigned int frame = 0; frame < frames; frame++)
+      {
+        std::auto_ptr<Slice> slice(new Slice);
+        if (slice->ParseOrthancFrame(dicom, instances[i], frame))
+        {
+          OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
+          slices_.AddSlice(geometry, slice.release());
+        }
+        else
+        {
+          LOG(WARNING) << "Skipping invalid frame " << frame << " within instance " << instances[i];
+        }
+      }
+    }
+    
+    SortAndFinalizeSlices();
+  }
+  
+  void OrthancSlicesLoader::ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& tags = message.GetJson();
+    const std::string& instanceId = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetInstanceId();
+
+    OrthancPlugins::FullOrthancDataset dataset(tags);
+    
+    Orthanc::DicomMap dicom;
+    OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
+
+    unsigned int frames;
+    if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
+    {
+      frames = 1;
+    }
+    
+    LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)";
+    
+    for (unsigned int frame = 0; frame < frames; frame++)
+    {
+      std::auto_ptr<Slice> slice(new Slice);
+      if (slice->ParseOrthancFrame(dicom, instanceId, frame))
+      {
+        OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
+        slices_.AddSlice(geometry, slice.release());
+      }
+      else
+      {
+        LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId;
+        BroadcastMessage(SliceGeometryErrorMessage(*this));
+        return;
+      }
+    }
+    
+    SortAndFinalizeSlices();
+  }
+  
+  
+  void OrthancSlicesLoader::ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& tags = message.GetJson();
+    const std::string& instanceId = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetInstanceId();
+    unsigned int frame = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetFrame();
+
+    OrthancPlugins::FullOrthancDataset dataset(tags);
+    
+    state_ = State_GeometryReady;
+    
+    Orthanc::DicomMap dicom;
+    OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
+    
+    std::auto_ptr<Slice> slice(new Slice);
+    if (slice->ParseOrthancFrame(dicom, instanceId, frame))
+    {
+      LOG(INFO) << "Loaded instance geometry " << instanceId;
+
+      OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
+      slices_.AddSlice(geometry, slice.release());
+      
+      BroadcastMessage(SliceGeometryReadyMessage(*this));
+    }
+    else
+    {
+      LOG(WARNING) << "Skipping invalid instance " << instanceId;
+      BroadcastMessage(SliceGeometryErrorMessage(*this));
+    }
+  }
+  
+  
+  void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message)
+  {
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
+    std::auto_ptr<Orthanc::ImageAccessor>  image;
+    
+    try
+    {
+      image.reset(new Orthanc::PngReader);
+      dynamic_cast<Orthanc::PngReader&>(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize());
+    }
+    catch (Orthanc::OrthancException&)
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+    
+    if (image->GetWidth() != operation.GetSlice().GetWidth() ||
+        image->GetHeight() != operation.GetSlice().GetHeight())
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+
+    if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() ==
+        Orthanc::PixelFormat_SignedGrayscale16)
+    {
+      if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
+      {
+        image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
+      }
+      else
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+    }
+    
+    NotifySliceImageSuccess(operation, *image);
+  }
+  
+  void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message)
+  {
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
+    std::auto_ptr<Orthanc::ImageAccessor>  image;
+
+    try
+    {
+      image.reset(new Orthanc::PamReader);
+      dynamic_cast<Orthanc::PamReader&>(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize());
+    }
+    catch (Orthanc::OrthancException&)
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+
+    if (image->GetWidth() != operation.GetSlice().GetWidth() ||
+        image->GetHeight() != operation.GetSlice().GetHeight())
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+
+    if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() ==
+        Orthanc::PixelFormat_SignedGrayscale16)
+    {
+      if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
+      {
+        image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
+      }
+      else
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+    }
+
+    NotifySliceImageSuccess(operation, *image);
+  }
+
+
+  void OrthancSlicesLoader::ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
+
+    const Json::Value& encoded = message.GetJson();
+    if (encoded.type() != Json::objectValue ||
+        !encoded.isMember("Orthanc") ||
+        encoded["Orthanc"].type() != Json::objectValue)
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+    
+    const Json::Value& info = encoded["Orthanc"];
+    if (!info.isMember("PixelData") ||
+        !info.isMember("Stretched") ||
+        !info.isMember("Compression") ||
+        info["Compression"].type() != Json::stringValue ||
+        info["PixelData"].type() != Json::stringValue ||
+        info["Stretched"].type() != Json::booleanValue ||
+        info["Compression"].asString() != "Jpeg")
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+    
+    bool isSigned = false;
+    bool isStretched = info["Stretched"].asBool();
+    
+    if (info.isMember("IsSigned"))
+    {
+      if (info["IsSigned"].type() != Json::booleanValue)
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+      else
+      {
+        isSigned = info["IsSigned"].asBool();
+      }
+    }
+    
+    std::auto_ptr<Orthanc::ImageAccessor> reader;
+    
+    {
+      std::string jpeg;
+      //Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString());
+      jpeg = base64_decode(info["PixelData"].asString());
+      
+      try
+      {
+        reader.reset(new Orthanc::JpegReader);
+        dynamic_cast<Orthanc::JpegReader&>(*reader).ReadFromMemory(jpeg);
+      }
+      catch (Orthanc::OrthancException&)
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+    }
+    
+    Orthanc::PixelFormat expectedFormat =
+      operation.GetSlice().GetConverter().GetExpectedPixelFormat();
+    
+    if (reader->GetFormat() == Orthanc::PixelFormat_RGB24)  // This is a color image
+    {
+      if (expectedFormat != Orthanc::PixelFormat_RGB24)
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+      
+      if (isSigned || isStretched)
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+      else
+      {
+        NotifySliceImageSuccess(operation, *reader);
+        return;
+      }
+    }
+    
+    if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8)
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+    
+    if (!isStretched)
+    {
+      if (expectedFormat != reader->GetFormat())
+      {
+        NotifySliceImageError(operation);
+        return;
+      }
+      else
+      {
+        NotifySliceImageSuccess(operation, *reader);
+        return;
+      }
+    }
+    
+    int32_t stretchLow = 0;
+    int32_t stretchHigh = 0;
+    
+    if (!info.isMember("StretchLow") ||
+        !info.isMember("StretchHigh") ||
+        info["StretchLow"].type() != Json::intValue ||
+        info["StretchHigh"].type() != Json::intValue)
+    {
+      NotifySliceImageError(operation);
+      return;
+    }
+    
+    stretchLow = info["StretchLow"].asInt();
+    stretchHigh = info["StretchHigh"].asInt();
+    
+    if (stretchLow < -32768 ||
+        stretchHigh > 65535 ||
+        (stretchLow < 0 && stretchHigh > 32767))
+    {
+      // This range cannot be represented with a uint16_t or an int16_t
+      NotifySliceImageError(operation);
+      return;
+    }
+    
+    // Decode a grayscale JPEG 8bpp image coming from the Web viewer
+    std::auto_ptr<Orthanc::ImageAccessor> image
+      (new Orthanc::Image(expectedFormat, reader->GetWidth(), reader->GetHeight(), false));
+
+    Orthanc::ImageProcessing::Convert(*image, *reader);
+    reader.reset();
+    
+    float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
+    
+    if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling))
+    {
+      float offset = static_cast<float>(stretchLow) / scaling;
+      Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
+    }
+    
+    NotifySliceImageSuccess(operation, *image);
+  }
+
+
+  class StringImage : public Orthanc::ImageAccessor
+  {
+  private:
+    std::string  buffer_;
+    
+  public:
+    StringImage(Orthanc::PixelFormat format,
+                unsigned int width,
+                unsigned int height,
+                std::string& buffer)
+    {
+      if (buffer.size() != Orthanc::GetBytesPerPixel(format) * width * height)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+      }
+      
+      buffer_.swap(buffer);  // The source buffer is now empty
+      
+      void* data = (buffer_.empty() ? NULL : &buffer_[0]);
+      
+      AssignWritable(format, width, height,
+                     Orthanc::GetBytesPerPixel(format) * width, data);
+    }
+  };
+  
+  void OrthancSlicesLoader::ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message)
+  {
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
+    Orthanc::GzipCompressor compressor;
+    
+    std::string raw;
+    compressor.Uncompress(raw, message.GetAnswer(), message.GetAnswerSize());
+    
+    const Orthanc::DicomImageInformation& info = operation.GetSlice().GetImageInformation();
+    
+    if (info.GetBitsAllocated() == 32 &&
+        info.GetBitsStored() == 32 &&
+        info.GetHighBit() == 31 &&
+        info.GetChannelCount() == 1 &&
+        !info.IsSigned() &&
+        info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 &&
+        raw.size() == info.GetWidth() * info.GetHeight() * 4)
+    {
+      // This is the case of RT-DOSE (uint32_t values)
+      
+      std::auto_ptr<Orthanc::ImageAccessor> image
+        (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(),
+                         info.GetHeight(), raw));
+      
+      // TODO - Only for big endian
+      for (unsigned int y = 0; y < image->GetHeight(); y++)
+      {
+        uint32_t *p = reinterpret_cast<uint32_t*>(image->GetRow(y));
+        for (unsigned int x = 0; x < image->GetWidth(); x++, p++)
+        {
+          *p = le32toh(*p);
+        }
+      }
+      
+      NotifySliceImageSuccess(operation, *image);
+    }
+    else if (info.GetBitsAllocated() == 16 &&
+             info.GetBitsStored() == 16 &&
+             info.GetHighBit() == 15 &&
+             info.GetChannelCount() == 1 &&
+             !info.IsSigned() &&
+             info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 &&
+             raw.size() == info.GetWidth() * info.GetHeight() * 2)
+    {
+      std::auto_ptr<Orthanc::ImageAccessor> image
+        (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(),
+                         info.GetHeight(), raw));
+      
+      // TODO - Big endian ?
+      
+      NotifySliceImageSuccess(operation, *image);
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+    }
+
+  }
+  
+  
+  OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
+                                           OrthancApiClient& orthanc) :
+    OrthancStone::IObservable(broker),
+    OrthancStone::IObserver(broker),
+    orthanc_(orthanc),
+    state_(State_Initialization)
+  {
+  }
+  
+  
+  void OrthancSlicesLoader::ScheduleLoadSeries(const std::string& seriesId)
+  {
+    if (state_ != State_Initialization)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      state_ = State_LoadingGeometry;
+      orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags",
+                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSeriesGeometry),
+                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
+                            NULL);
+    }
+  }
+  
+  void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId)
+  {
+    if (state_ != State_Initialization)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      state_ = State_LoadingGeometry;
+      
+      // Tag "3004-000c" is "Grid Frame Offset Vector", which is
+      // mandatory to read RT DOSE, but is too long to be returned by default
+      orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c",
+                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseInstanceGeometry),
+                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
+                            Operation::DownloadInstanceGeometry(instanceId));
+    }
+  }
+  
+  
+  void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId,
+                                              unsigned int frame)
+  {
+    if (state_ != State_Initialization)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      state_ = State_LoadingGeometry;
+
+      orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags",
+                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseFrameGeometry),
+                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
+                            Operation::DownloadFrameGeometry(instanceId, frame));
+    }
+  }
+  
+  
+  bool OrthancSlicesLoader::IsGeometryReady() const
+  {
+    return state_ == State_GeometryReady;
+  }
+  
+  
+  size_t OrthancSlicesLoader::GetSlicesCount() const
+  {
+    if (state_ != State_GeometryReady)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    return slices_.GetSlicesCount();
+  }
+  
+  
+  const Slice& OrthancSlicesLoader::GetSlice(size_t index) const
+  {
+    if (state_ != State_GeometryReady)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    return dynamic_cast<const Slice&>(slices_.GetSlicePayload(index));
+  }
+  
+  
+  bool OrthancSlicesLoader::LookupSlice(size_t& index,
+                                        const OrthancStone::CoordinateSystem3D& plane) const
+  {
+    if (state_ != State_GeometryReady)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    double distance;
+    return (slices_.LookupClosestSlice(index, distance, plane) &&
+            distance <= GetSlice(index).GetThickness() / 2.0);
+  }
+  
+  
+  void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice,
+                                                  size_t index)
+  {
+    std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
+                       boost::lexical_cast<std::string>(slice.GetFrame()));
+    
+    switch (slice.GetConverter().GetExpectedPixelFormat())
+    {
+      case Orthanc::PixelFormat_RGB24:
+        uri += "/preview";
+        break;
+      
+      case Orthanc::PixelFormat_Grayscale16:
+        uri += "/image-uint16";
+        break;
+      
+      case Orthanc::PixelFormat_SignedGrayscale16:
+        uri += "/image-int16";
+        break;
+      
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    
+    orthanc_.GetBinaryAsync(uri, "image/png",
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        OrthancApiClient::BinaryResponseReadyMessage>
+          (*this, &OrthancSlicesLoader::ParseSliceImagePng),
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        IWebService::HttpRequestErrorMessage>
+          (*this, &OrthancSlicesLoader::OnSliceImageError),
+      Operation::DownloadSliceImage(
+        static_cast<unsigned int>(index), slice, OrthancStone::SliceImageQuality_FullPng));
+}
+  
+  void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice,
+                                                  size_t index)
+  {
+    std::string uri = 
+      ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
+      boost::lexical_cast<std::string>(slice.GetFrame()));
+
+    switch (slice.GetConverter().GetExpectedPixelFormat())
+    {
+      case Orthanc::PixelFormat_RGB24:
+        uri += "/preview";
+        break;
+
+      case Orthanc::PixelFormat_Grayscale16:
+        uri += "/image-uint16";
+        break;
+
+      case Orthanc::PixelFormat_SignedGrayscale16:
+        uri += "/image-int16";
+        break;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap",
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        OrthancApiClient::BinaryResponseReadyMessage>
+          (*this, &OrthancSlicesLoader::ParseSliceImagePam),
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        IWebService::HttpRequestErrorMessage>
+          (*this, &OrthancSlicesLoader::OnSliceImageError),
+      Operation::DownloadSliceImage(static_cast<unsigned int>(index), 
+                                    slice, OrthancStone::SliceImageQuality_FullPam));
+  }
+
+
+  
+  void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice,
+                                                   size_t index,
+                                                   OrthancStone::SliceImageQuality quality)
+  {
+    unsigned int value;
+    
+    switch (quality)
+    {
+      case OrthancStone::SliceImageQuality_Jpeg50:
+        value = 50;
+        break;
+
+      case OrthancStone::SliceImageQuality_Jpeg90:
+        value = 90;
+        break;
+
+      case OrthancStone::SliceImageQuality_Jpeg95:
+        value = 95;
+        break;
+      
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    
+    // This requires the official Web viewer plugin to be installed!
+    std::string uri = ("/web-viewer/instances/jpeg" +
+                       boost::lexical_cast<std::string>(value) +
+                       "-" + slice.GetOrthancInstanceId() + "_" +
+                       boost::lexical_cast<std::string>(slice.GetFrame()));
+
+    orthanc_.GetJsonAsync(uri,
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        OrthancApiClient::JsonResponseReadyMessage>
+          (*this, &OrthancSlicesLoader::ParseSliceImageJpeg),
+      new OrthancStone::Callable<OrthancSlicesLoader, 
+        IWebService::HttpRequestErrorMessage>
+          (*this, &OrthancSlicesLoader::OnSliceImageError),
+        Operation::DownloadSliceImage(
+          static_cast<unsigned int>(index), slice, quality));
+  }
+  
+  
+  
+  void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index,
+                                                   OrthancStone::SliceImageQuality quality)
+  {
+    if (state_ != State_GeometryReady)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    const Slice& slice = GetSlice(index);
+    
+    if (slice.HasOrthancDecoding())
+    {
+      switch (quality)
+      {
+        case OrthancStone::SliceImageQuality_FullPng:
+          ScheduleSliceImagePng(slice, index);
+          break;
+        case OrthancStone::SliceImageQuality_FullPam:
+          ScheduleSliceImagePam(slice, index);
+          break;
+        default:
+          ScheduleSliceImageJpeg(slice, index, quality);
+      }
+    }
+    else
+    {
+      std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
+                         boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz");
+      orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(),
+        new OrthancStone::Callable<OrthancSlicesLoader, 
+          OrthancApiClient::BinaryResponseReadyMessage>
+            (*this, &OrthancSlicesLoader::ParseSliceRawImage),
+        new OrthancStone::Callable<OrthancSlicesLoader,
+          IWebService::HttpRequestErrorMessage>
+            (*this, &OrthancSlicesLoader::OnSliceImageError),
+        Operation::DownloadSliceRawImage(
+          static_cast<unsigned int>(index), slice));
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,209 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Messages/IObservable.h"
+#include "../../StoneEnumerations.h"
+#include "IWebService.h"
+#include "OrthancApiClient.h"
+#include "../../Toolbox/SlicesSorter.h"
+#include "Slice.h"
+
+#include <Core/Images/Image.h>
+
+
+namespace Deprecated
+{
+  class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryErrorMessage, OrthancSlicesLoader);
+
+    
+    class SliceImageReadyMessage : public OrthancStone::OriginMessage<OrthancSlicesLoader>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      unsigned int                   sliceIndex_;
+      const Slice&                   slice_;
+      const Orthanc::ImageAccessor&  image_;
+      OrthancStone::SliceImageQuality  effectiveQuality_;
+
+    public:
+      SliceImageReadyMessage(const OrthancSlicesLoader& origin,
+                             unsigned int sliceIndex,
+                             const Slice& slice,
+                             const Orthanc::ImageAccessor& image,
+                             OrthancStone::SliceImageQuality effectiveQuality) :
+        OriginMessage(origin),
+        sliceIndex_(sliceIndex),
+        slice_(slice),
+        image_(image),
+        effectiveQuality_(effectiveQuality)
+      {
+      }
+
+      unsigned int GetSliceIndex() const
+      {
+        return sliceIndex_;
+      }
+
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+
+      const Orthanc::ImageAccessor& GetImage() const
+      {
+        return image_;
+      }
+
+      OrthancStone::SliceImageQuality GetEffectiveQuality() const
+      {
+        return effectiveQuality_;
+      }        
+    };
+    
+
+    class SliceImageErrorMessage : public OrthancStone::OriginMessage<OrthancSlicesLoader>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      const Slice&       slice_;
+      unsigned int       sliceIndex_;
+      OrthancStone::SliceImageQuality  effectiveQuality_;
+
+    public:
+      SliceImageErrorMessage(const OrthancSlicesLoader& origin,
+                             unsigned int sliceIndex,
+                             const Slice& slice,
+                             OrthancStone::SliceImageQuality effectiveQuality) :
+        OriginMessage(origin),
+        slice_(slice),
+        sliceIndex_(sliceIndex),
+        effectiveQuality_(effectiveQuality)
+      {
+      }
+      unsigned int GetSliceIndex() const
+      {
+        return sliceIndex_;
+      }
+
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+
+      OrthancStone::SliceImageQuality GetEffectiveQuality() const
+      {
+        return effectiveQuality_;
+      }        
+    };
+    
+  private:
+    enum State
+    {
+      State_Error,
+      State_Initialization,
+      State_LoadingGeometry,
+      State_GeometryReady
+    };
+    
+    enum Mode
+    {
+      Mode_SeriesGeometry,
+      Mode_InstanceGeometry,
+      Mode_FrameGeometry,
+      Mode_LoadImage,
+      Mode_LoadRawImage,
+      Mode_LoadDicomFile
+    };
+
+    class Operation;
+
+    OrthancApiClient&  orthanc_;
+    State         state_;
+    OrthancStone::SlicesSorter  slices_;
+
+    void NotifySliceImageSuccess(const Operation& operation,
+                                 const Orthanc::ImageAccessor& image);
+    
+    void NotifySliceImageError(const Operation& operation);
+
+    void OnGeometryError(const IWebService::HttpRequestErrorMessage& message);
+
+    void OnSliceImageError(const IWebService::HttpRequestErrorMessage& message);
+
+    void ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message);
+
+    void ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message);
+
+    void ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message);
+
+    void ScheduleSliceImagePng(const Slice& slice,
+                               size_t index);
+
+    void ScheduleSliceImagePam(const Slice& slice,
+                               size_t index);
+
+    void ScheduleSliceImageJpeg(const Slice& slice,
+                                size_t index,
+                                OrthancStone::SliceImageQuality quality);
+
+    void SortAndFinalizeSlices();
+    
+  public:
+    OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
+                        //ISliceLoaderObserver& callback,
+                        OrthancApiClient& orthancApi);
+
+    void ScheduleLoadSeries(const std::string& seriesId);
+
+    void ScheduleLoadInstance(const std::string& instanceId);
+
+    void ScheduleLoadFrame(const std::string& instanceId,
+                           unsigned int frame);
+
+    bool IsGeometryReady() const;
+
+    size_t GetSlicesCount() const;
+
+    const Slice& GetSlice(size_t index) const;
+
+    bool LookupSlice(size_t& index,
+                     const OrthancStone::CoordinateSystem3D& plane) const;
+
+    void ScheduleLoadSliceImage(size_t index,
+                                OrthancStone::SliceImageQuality requestedQuality);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/Slice.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,367 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "Slice.h"
+
+#include "../../StoneEnumerations.h"
+#include "../../Toolbox/GeometryToolbox.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <Core/Toolbox.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace Deprecated
+{
+  static bool ParseDouble(double& target,
+                          const std::string& source)
+  {
+    try
+    {
+      target = boost::lexical_cast<double>(source);
+      return true;
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      return false;
+    }
+  }
+
+  Slice* Slice::Clone() const
+  {
+    std::auto_ptr<Slice> target(new Slice());
+
+    target->type_ = type_;
+    target->orthancInstanceId_ = orthancInstanceId_;
+    target->sopClassUid_ = sopClassUid_;
+    target->frame_ = frame_;
+    target->frameCount_ = frameCount_;
+    target->geometry_ = geometry_;
+    target->pixelSpacingX_ = pixelSpacingX_;
+    target->pixelSpacingY_ = pixelSpacingY_;
+    target->thickness_ = thickness_;
+    target->width_ = width_;
+    target->height_ = height_;
+    target->converter_ = converter_;
+    if (imageInformation_.get() != NULL)
+      target->imageInformation_.reset(imageInformation_->Clone());
+
+    return target.release();
+  }
+  
+  bool Slice::ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset,
+                                    unsigned int frame)
+  {
+    // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html
+
+    {
+      std::string increment;
+
+      if (dataset.CopyToString(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false))
+      {
+        Orthanc::Toolbox::ToUpperCase(increment);
+        if (increment != "3004,000C")  // This is the "Grid Frame Offset Vector" tag
+        {
+          LOG(ERROR) << "Bad value for the \"FrameIncrementPointer\" tag";
+          return false;
+        }
+      }
+    }
+
+    std::string offsetTag;
+
+    if (!dataset.CopyToString(offsetTag, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, false) ||
+        offsetTag.empty())
+    {
+      LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1";
+      return false;
+    }
+
+    std::vector<std::string> offsets;
+    Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\');
+
+    if (frameCount_ <= 1 ||
+        offsets.size() < frameCount_ ||
+        offsets.size() < 2 ||
+        frame >= frameCount_)
+    {
+      LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE";
+      return false;
+    }
+
+    double offset0, offset1, z;
+
+    if (!ParseDouble(offset0, offsets[0]) ||
+        !ParseDouble(offset1, offsets[1]) ||
+        !ParseDouble(z, offsets[frame]))
+    {
+      LOG(ERROR) << "Invalid syntax";
+      return false;
+    }
+
+    if (!OrthancStone::LinearAlgebra::IsCloseToZero(offset0))
+    {
+      LOG(ERROR) << "Invalid syntax";
+      return false;
+    }
+
+    geometry_ = OrthancStone::CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
+                                                 //+ 650 * geometry_.GetAxisX(),
+                                                 geometry_.GetAxisX(),
+                                                 geometry_.GetAxisY());
+
+    thickness_ = offset1 - offset0;
+    if (thickness_ < 0)
+    {
+      thickness_ = -thickness_;
+    }
+
+    return true;
+  }
+
+  
+  bool Slice::ParseOrthancFrame(const Orthanc::DicomMap& dataset,
+                                const std::string& instanceId,
+                                unsigned int frame)
+  {
+    orthancInstanceId_ = instanceId;
+    frame_ = frame;
+    type_ = Type_OrthancDecodableFrame;
+    imageInformation_.reset(new Orthanc::DicomImageInformation(dataset));
+
+    if (!dataset.CopyToString(sopClassUid_, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) ||
+        sopClassUid_.empty())
+    {
+      LOG(ERROR) << "Instance without a SOP class UID";
+      return false; 
+    }
+
+    if (!dataset.ParseUnsignedInteger32(frameCount_, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
+    {
+      frameCount_ = 1;   // Assume instance with one frame
+    }
+
+    if (frame >= frameCount_)
+    {
+      return false;
+    }
+
+    if (!dataset.ParseUnsignedInteger32(width_, Orthanc::DICOM_TAG_COLUMNS) ||
+        !dataset.ParseUnsignedInteger32(height_, Orthanc::DICOM_TAG_ROWS))
+    {
+      return false;
+    }
+
+    thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
+
+    std::string tmp;
+    if (dataset.CopyToString(tmp, Orthanc::DICOM_TAG_SLICE_THICKNESS, false))
+    {
+      if (!tmp.empty() &&
+          !ParseDouble(thickness_, tmp))
+      {
+        return false;  // Syntax error
+      }
+    }
+    
+    converter_.ReadParameters(dataset);
+
+    OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
+
+    std::string position, orientation;
+    if (dataset.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) &&
+        dataset.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false))
+    {
+      geometry_ = OrthancStone::CoordinateSystem3D(position, orientation);
+
+      bool ok = true;
+
+      switch (OrthancStone::StringToSopClassUid(sopClassUid_))
+      {
+        case OrthancStone::SopClassUid_RTDose:
+          type_ = Type_OrthancRawFrame;
+          ok = ComputeRTDoseGeometry(dataset, frame);
+          break;
+            
+        default:
+          break;
+      }
+
+      if (!ok)
+      {
+        LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame
+                   << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_;
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  
+  const std::string Slice::GetOrthancInstanceId() const
+  {
+    if (type_ == Type_OrthancDecodableFrame ||
+        type_ == Type_OrthancRawFrame)
+    {
+      return orthancInstanceId_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }   
+  }
+
+  
+  unsigned int Slice::GetFrame() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return frame_;
+  }
+
+  
+  const OrthancStone::CoordinateSystem3D& Slice::GetGeometry() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return geometry_;
+  }
+
+  
+  double Slice::GetThickness() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return thickness_;
+  }
+
+  
+  double Slice::GetPixelSpacingX() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return pixelSpacingX_;
+  }
+
+  
+  double Slice::GetPixelSpacingY() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return pixelSpacingY_;
+  }
+
+  
+  unsigned int Slice::GetWidth() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return width_;
+  }
+
+  
+  unsigned int Slice::GetHeight() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return height_;
+  }
+
+
+  const DicomFrameConverter& Slice::GetConverter() const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+        
+    return converter_;
+  }
+
+
+  bool Slice::ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
+  {
+    if (type_ == Type_Invalid)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+
+    bool opposite;
+    return (OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite,
+                                                                GetGeometry().GetNormal(),
+                                                                plane.GetNormal()) &&
+            OrthancStone::LinearAlgebra::IsNear(GetGeometry().ProjectAlongNormal(GetGeometry().GetOrigin()),
+                                                GetGeometry().ProjectAlongNormal(plane.GetOrigin()),
+                                                thickness_ / 2.0));
+  }
+
+  
+  void Slice::GetExtent(std::vector<OrthancStone::Vector>& points) const
+  {
+    double sx = GetPixelSpacingX();
+    double sy = GetPixelSpacingY();
+    double w = static_cast<double>(GetWidth());
+    double h = static_cast<double>(GetHeight());
+
+    points.clear();
+    points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5      * sx, -0.5      * sy));
+    points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, -0.5      * sy));
+    points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5      * sx, (h - 0.5) * sy));
+    points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, (h - 0.5) * sy));
+  }
+
+
+  const Orthanc::DicomImageInformation& Slice::GetImageInformation() const
+  {
+    if (imageInformation_.get() == NULL)
+    {
+      // Only available if constructing the "Slice" object with a DICOM map
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      return *imageInformation_;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/Slice.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,155 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Toolbox/CoordinateSystem3D.h"
+#include "DicomFrameConverter.h"
+
+#include <Core/DicomFormat/DicomImageInformation.h>
+#include <Core/IDynamicObject.h>
+
+namespace Deprecated
+{
+  // TODO - Remove this class
+  class Slice :
+    public Orthanc::IDynamicObject  /* to be used as a payload of SlicesSorter */
+  {
+  private:
+    enum Type
+    {
+      Type_Invalid,
+      Type_Standalone,
+      Type_OrthancDecodableFrame,
+      Type_OrthancRawFrame
+      // TODO A slice could come from some DICOM file (URL)
+    };
+
+    bool ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset,
+                               unsigned int frame);
+
+    Type                 type_;
+    std::string          orthancInstanceId_;
+    std::string          sopClassUid_;
+    unsigned int         frame_;
+    unsigned int         frameCount_;   // TODO : Redundant with "imageInformation_"
+    OrthancStone::CoordinateSystem3D   geometry_;
+    double               pixelSpacingX_;
+    double               pixelSpacingY_;
+    double               thickness_;
+    unsigned int         width_;   // TODO : Redundant with "imageInformation_"
+    unsigned int         height_;   // TODO : Redundant with "imageInformation_"
+    DicomFrameConverter  converter_;   // TODO : Partially redundant with "imageInformation_"
+
+    std::auto_ptr<Orthanc::DicomImageInformation>  imageInformation_;
+
+  public:
+    Slice() :
+      type_(Type_Invalid)
+    {
+    }
+
+
+    // this constructor is used to reference, i.e, a slice that is being loaded
+    Slice(const std::string& orthancInstanceId,
+          unsigned int frame) :
+      type_(Type_Invalid),
+      orthancInstanceId_(orthancInstanceId),
+      frame_(frame)
+    {        
+    }
+
+    // TODO Is this constructor the best way to go to tackle missing
+    // layers within SliceViewerWidget?
+    Slice(const OrthancStone::CoordinateSystem3D& plane,
+          double thickness) :
+      type_(Type_Standalone),
+      frame_(0),
+      frameCount_(0),
+      geometry_(plane),
+      pixelSpacingX_(1),
+      pixelSpacingY_(1),
+      thickness_(thickness),
+      width_(0),
+      height_(0)
+    {      
+    }
+
+    Slice(const OrthancStone::CoordinateSystem3D& plane,
+          double pixelSpacingX,
+          double pixelSpacingY,
+          double thickness,
+          unsigned int width,
+          unsigned int height,
+          const DicomFrameConverter& converter) :
+      type_(Type_Standalone),
+      frameCount_(1),
+      geometry_(plane),
+      pixelSpacingX_(pixelSpacingX),
+      pixelSpacingY_(pixelSpacingY),
+      thickness_(thickness),
+      width_(width),
+      height_(height),
+      converter_(converter)
+    {
+    }
+
+    bool IsValid() const
+    {
+      return type_ != Type_Invalid;
+    } 
+
+    bool ParseOrthancFrame(const Orthanc::DicomMap& dataset,
+                           const std::string& instanceId,
+                           unsigned int frame);
+
+    bool HasOrthancDecoding() const
+    {
+      return type_ == Type_OrthancDecodableFrame;
+    }
+
+    const std::string GetOrthancInstanceId() const;
+
+    unsigned int GetFrame() const;
+
+    const OrthancStone::CoordinateSystem3D& GetGeometry() const;
+
+    double GetThickness() const;
+
+    double GetPixelSpacingX() const;
+
+    double GetPixelSpacingY() const;
+
+    unsigned int GetWidth() const;
+
+    unsigned int GetHeight() const;
+
+    const DicomFrameConverter& GetConverter() const;
+
+    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const;
+
+    void GetExtent(std::vector<OrthancStone::Vector>& points) const;
+
+    const Orthanc::DicomImageInformation& GetImageInformation() const;
+
+    Slice* Clone() const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/ViewportGeometry.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,217 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ViewportGeometry.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/math/special_functions/round.hpp>
+
+namespace Deprecated
+{
+  void ViewportGeometry::ComputeTransform()
+  {
+    // The following lines must be read in reverse order!
+    cairo_matrix_t tmp;
+    
+    // Bring the center of the scene to the center of the view
+    cairo_matrix_init_translate(&transform_, 
+                                panX_ + static_cast<double>(width_) / 2.0, 
+                                panY_ + static_cast<double>(height_) / 2.0);
+
+    // Apply the zoom around (0,0)
+    cairo_matrix_init_scale(&tmp, zoom_, zoom_);
+    cairo_matrix_multiply(&transform_, &tmp, &transform_);
+
+    // Bring the center of the scene to (0,0)
+    cairo_matrix_init_translate(&tmp,
+                                -(sceneExtent_.GetX1() + sceneExtent_.GetX2()) / 2.0,
+                                -(sceneExtent_.GetY1() + sceneExtent_.GetY2()) / 2.0);
+    cairo_matrix_multiply(&transform_, &tmp, &transform_);
+  }
+
+
+  ViewportGeometry::ViewportGeometry()
+  {
+    width_ = 0;
+    height_ = 0;
+
+    zoom_ = 1;
+    panX_ = 0;
+    panY_ = 0;
+
+    ComputeTransform();
+  }
+
+
+  void ViewportGeometry::SetDisplaySize(unsigned int width,
+                                        unsigned int height)
+  {
+    if (width_ != width ||
+        height_ != height)
+    {
+      LOG(INFO) << "New display size: " << width << "x" << height;
+
+      width_ = width;
+      height_ = height;
+
+      ComputeTransform();
+    }
+  }
+
+
+  void ViewportGeometry::SetSceneExtent(const OrthancStone::Extent2D& extent)
+  {
+    LOG(INFO) << "New scene extent: ("
+              << extent.GetX1() << "," << extent.GetY1() << ") => ("
+              << extent.GetX2() << "," << extent.GetY2() << ")";
+
+    sceneExtent_ = extent;
+    ComputeTransform();
+  }
+
+
+  void ViewportGeometry::MapDisplayToScene(double& sceneX /* out */,
+                                           double& sceneY /* out */,
+                                           double x,
+                                           double y) const
+  {
+    cairo_matrix_t transform = transform_;
+
+    if (cairo_matrix_invert(&transform) != CAIRO_STATUS_SUCCESS)
+    {
+      LOG(ERROR) << "Cannot invert singular matrix";
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+
+    sceneX = x;
+    sceneY = y;
+    cairo_matrix_transform_point(&transform, &sceneX, &sceneY);
+  }
+
+
+  void ViewportGeometry::MapSceneToDisplay(int& displayX /* out */,
+                                           int& displayY /* out */,
+                                           double x,
+                                           double y) const
+  {
+    cairo_matrix_transform_point(&transform_, &x, &y);
+
+    displayX = static_cast<int>(boost::math::iround(x));
+    displayY = static_cast<int>(boost::math::iround(y));
+  }
+
+
+  void ViewportGeometry::MapPixelCenterToScene(std::vector<Touch>& sceneTouches /* out */,
+                                               const std::vector<Touch>& displayTouches) const
+  {
+    double sceneX, sceneY;
+    sceneTouches.clear();
+    for (size_t t = 0; t < displayTouches.size(); t++)
+    {
+      MapPixelCenterToScene(
+        sceneX,
+        sceneY, 
+        static_cast<int>(displayTouches[t].x), 
+        static_cast<int>(displayTouches[t].y));
+      
+      sceneTouches.push_back(Touch((float)sceneX, (float)sceneY));
+    }
+  }
+
+  void ViewportGeometry::MapPixelCenterToScene(double& sceneX,
+                                               double& sceneY,
+                                               int x,
+                                               int y) const
+  {
+    // Take the center of the pixel
+    MapDisplayToScene(sceneX, sceneY,
+                      static_cast<double>(x) + 0.5,
+                      static_cast<double>(y) + 0.5);
+  }
+
+
+  void ViewportGeometry::FitContent()
+  {
+    if (width_ > 0 &&
+        height_ > 0 &&
+        !sceneExtent_.IsEmpty())
+    {
+      double zoomX = static_cast<double>(width_) / (sceneExtent_.GetX2() - sceneExtent_.GetX1());
+      double zoomY = static_cast<double>(height_) / (sceneExtent_.GetY2() - sceneExtent_.GetY1());
+      zoom_ = zoomX < zoomY ? zoomX : zoomY;
+
+      panX_ = 0;
+      panY_ = 0;
+
+      ComputeTransform();
+    }
+  }
+
+
+  void ViewportGeometry::ApplyTransform(OrthancStone::CairoContext& context) const
+  {
+    cairo_set_matrix(context.GetObject(), &transform_);
+  }
+
+
+  void ViewportGeometry::GetPan(double& x,
+                                double& y) const
+  {
+    x = panX_;
+    y = panY_;
+  }
+
+
+  void ViewportGeometry::SetPan(double x,
+                                double y)
+  {
+    panX_ = x;
+    panY_ = y;
+    ComputeTransform();
+  }
+
+
+  void ViewportGeometry::SetZoom(double zoom)
+  {
+    zoom_ = zoom;
+    ComputeTransform();
+  }
+
+
+  OrthancStone::Matrix ViewportGeometry::GetMatrix() const
+  {
+    OrthancStone::Matrix m(3, 3);
+
+    m(0, 0) = transform_.xx;
+    m(0, 1) = transform_.xy;
+    m(0, 2) = transform_.x0;
+    m(1, 0) = transform_.yx;
+    m(1, 1) = transform_.yy;
+    m(1, 2) = transform_.y0;
+    m(2, 0) = 0;
+    m(2, 1) = 0;
+    m(2, 2) = 1;
+    
+    return m;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Toolbox/ViewportGeometry.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,110 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Viewport/CairoContext.h"
+#include "../../Toolbox/Extent2D.h"
+#include "../../Toolbox/LinearAlgebra.h"
+#include "../Viewport/IMouseTracker.h"  // to include "Touch" definition
+
+namespace Deprecated
+{
+  class ViewportGeometry
+  {
+  private:
+    // Extent of the scene (in world units)
+    OrthancStone::Extent2D   sceneExtent_;
+
+    // Size of the display (in pixels)
+    unsigned int  width_;
+    unsigned int  height_;
+
+    // Zoom/pan
+    double   zoom_;
+    double   panX_;  // In pixels (display units)
+    double   panY_;
+
+    cairo_matrix_t  transform_;  // Scene-to-display transformation
+
+    void ComputeTransform();
+
+  public:
+    ViewportGeometry();
+
+    void SetDisplaySize(unsigned int width,
+                        unsigned int height);
+
+    void SetSceneExtent(const OrthancStone::Extent2D& extent);
+
+    const OrthancStone::Extent2D& GetSceneExtent() const
+    {
+      return sceneExtent_;
+    }
+
+    void MapDisplayToScene(double& sceneX /* out */,
+                           double& sceneY /* out */,
+                           double x,
+                           double y) const;
+
+    void MapPixelCenterToScene(double& sceneX /* out */,
+                               double& sceneY /* out */,
+                               int x,
+                               int y) const;
+
+    void MapPixelCenterToScene(std::vector<Touch>& sceneTouches /* out */,
+                               const std::vector<Touch>& displayTouches) const;
+
+    void MapSceneToDisplay(int& displayX /* out */,
+                           int& displayY /* out */,
+                           double x,
+                           double y) const;
+
+    unsigned int GetDisplayWidth() const
+    {
+      return width_;
+    }
+
+    unsigned int GetDisplayHeight() const
+    {
+      return height_;
+    }
+
+    double GetZoom() const
+    {
+      return zoom_;
+    }
+
+    void FitContent();
+
+    void ApplyTransform(OrthancStone::CairoContext& context) const;
+
+    void GetPan(double& x,
+                double& y) const;
+
+    void SetPan(double x,
+                double y);
+
+    void SetZoom(double zoom);
+
+    OrthancStone::Matrix GetMatrix() const;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Viewport/IMouseTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,66 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Viewport/CairoSurface.h"
+#include <vector>
+
+namespace Deprecated
+{
+  struct Touch
+  {
+    float x;
+    float y;
+
+    Touch(float x, float y)
+    : x(x),
+      y(y)
+    {
+    }
+    Touch()
+      : x(0.0f),
+        y(0.0f)
+    {
+    }
+  };
+
+
+  // this is tracking a mouse in screen coordinates/pixels unlike
+  // the IWorldSceneMouseTracker that is tracking a mouse
+  // in scene coordinates/mm.
+  class IMouseTracker : public boost::noncopyable
+  {
+  public:
+    virtual ~IMouseTracker()
+    {
+    }
+    
+    virtual void Render(Orthanc::ImageAccessor& surface) = 0;
+
+    virtual void MouseUp() = 0;
+
+    // Returns "true" iff. the background scene must be repainted
+    virtual void MouseMove(int x, 
+                           int y,
+                           const std::vector<Touch>& displayTouches) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Viewport/IStatusBar.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,40 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 <boost/noncopyable.hpp>
+
+namespace Deprecated
+{
+  class IStatusBar : public boost::noncopyable
+  {
+  public:
+    virtual ~IStatusBar()
+    {
+    }
+    
+    virtual void ClearMessage() = 0;
+
+    virtual void SetMessage(const std::string& message) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Viewport/IViewport.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,95 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IStatusBar.h"
+#include "../../StoneEnumerations.h"
+#include "../../Messages/IObservable.h"
+
+#include <Core/Images/ImageAccessor.h>
+#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition
+
+namespace Deprecated
+{
+  class IWidget;   // Forward declaration
+  
+  class IViewport : public OrthancStone::IObservable
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport);
+
+    IViewport(OrthancStone::MessageBroker& broker) :
+      IObservable(broker)
+    {
+    }
+    
+    virtual ~IViewport()
+    {
+    }
+
+    virtual void FitContent() = 0;
+
+    virtual void SetStatusBar(IStatusBar& statusBar) = 0;
+
+    virtual void SetSize(unsigned int width,
+                         unsigned int height) = 0;
+
+    // The function returns "true" iff. a new frame was rendered
+    virtual bool Render(Orthanc::ImageAccessor& surface) = 0;
+
+    virtual void MouseDown(OrthancStone::MouseButton button,
+                           int x,
+                           int y,
+                           OrthancStone::KeyboardModifiers modifiers,
+                           const std::vector<Touch>& touches) = 0;
+
+    virtual void MouseUp() = 0;
+
+    virtual void MouseMove(int x, 
+                           int y,
+                           const std::vector<Touch>& displayTouches) = 0;
+
+    virtual void MouseEnter() = 0;
+
+    virtual void MouseLeave() = 0;
+
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                            int x,
+                            int y,
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
+
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
+
+    virtual bool HasAnimation() = 0;
+
+    virtual void DoAnimation() = 0;
+
+    // Should only be called from IWidget
+    // TODO Why should this be virtual?
+    virtual void NotifyContentChanged()
+    {
+      BroadcastMessage(ViewportChangedMessage(*this));
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Viewport/WidgetViewport.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,289 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WidgetViewport.h"
+
+#include <Core/Images/ImageProcessing.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) :
+    IViewport(broker),
+    statusBar_(NULL),
+    isMouseOver_(false),
+    lastMouseX_(0),
+    lastMouseY_(0),
+    backgroundChanged_(false)
+  {
+  }
+
+
+  void WidgetViewport::FitContent()
+  {
+    if (centralWidget_.get() != NULL)
+    {
+      centralWidget_->FitContent();
+    }
+  }
+
+
+  void WidgetViewport::SetStatusBar(IStatusBar& statusBar)
+  {
+    statusBar_ = &statusBar;
+
+    if (centralWidget_.get() != NULL)
+    {
+      centralWidget_->SetStatusBar(statusBar);
+    }
+  }
+
+
+  IWidget& WidgetViewport::SetCentralWidget(IWidget* widget)
+  {
+    if (widget == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    mouseTracker_.reset(NULL);
+
+    centralWidget_.reset(widget);
+    centralWidget_->SetViewport(*this);
+
+    if (statusBar_ != NULL)
+    {
+      centralWidget_->SetStatusBar(*statusBar_);
+    }
+
+    NotifyBackgroundChanged();
+
+    return *widget;
+  }
+
+
+  void WidgetViewport::NotifyBackgroundChanged()
+  {
+    backgroundChanged_ = true;
+    NotifyContentChanged();
+  }
+
+
+  void WidgetViewport::SetSize(unsigned int width,
+                               unsigned int height)
+  {
+    background_.SetSize(width, height, false /* no alpha */);
+
+    if (centralWidget_.get() != NULL)
+    {
+      centralWidget_->SetSize(width, height);
+    }
+
+    NotifyBackgroundChanged();
+  }
+
+
+  bool WidgetViewport::Render(Orthanc::ImageAccessor& surface)
+  {
+    if (centralWidget_.get() == NULL)
+    {
+      return false;
+    }
+
+    Orthanc::ImageAccessor background;
+    background_.GetWriteableAccessor(background);
+
+    if (backgroundChanged_ &&
+        !centralWidget_->Render(background))
+    {
+      return false;
+    }
+
+    if (background.GetWidth() != surface.GetWidth() ||
+        background.GetHeight() != surface.GetHeight())
+    {
+      return false;
+    }
+
+    Orthanc::ImageProcessing::Convert(surface, background);
+    
+    if (mouseTracker_.get() != NULL)
+    {
+      mouseTracker_->Render(surface);
+    }
+    else if (isMouseOver_)
+    {
+      centralWidget_->RenderMouseOver(surface, lastMouseX_, lastMouseY_);
+    }
+
+    return true;
+  }
+
+  void WidgetViewport::TouchStart(const std::vector<Touch>& displayTouches)
+  {
+    MouseDown(OrthancStone::MouseButton_Left, (int)displayTouches[0].x, (int)displayTouches[0].y, OrthancStone::KeyboardModifiers_None, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates
+  }
+      
+  void WidgetViewport::TouchMove(const std::vector<Touch>& displayTouches)
+  {
+    MouseMove((int)displayTouches[0].x, (int)displayTouches[0].y, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates
+  }
+      
+  void WidgetViewport::TouchEnd(const std::vector<Touch>& displayTouches)
+  {
+    // note: TouchEnd is not triggered when a single touch gesture ends (it is only triggered when
+    // going from 2 touches to 1 touch, ...)
+    MouseUp();
+  }
+
+  void WidgetViewport::MouseDown(OrthancStone::MouseButton button,
+                                 int x,
+                                 int y,
+                                 OrthancStone::KeyboardModifiers modifiers,
+                                 const std::vector<Touch>& displayTouches
+                                 )
+  {
+    lastMouseX_ = x;
+    lastMouseY_ = y;
+
+    if (centralWidget_.get() != NULL)
+    {
+      mouseTracker_.reset(centralWidget_->CreateMouseTracker(button, x, y, modifiers, displayTouches));
+    }
+    else
+    {
+      mouseTracker_.reset(NULL);
+    }      
+
+    NotifyContentChanged();
+  }
+
+
+  void WidgetViewport::MouseUp()
+  {
+    if (mouseTracker_.get() != NULL)
+    {
+      mouseTracker_->MouseUp();
+      mouseTracker_.reset(NULL);
+      NotifyContentChanged();
+    }
+  }
+
+
+  void WidgetViewport::MouseMove(int x, 
+                                 int y,
+                                 const std::vector<Touch>& displayTouches)
+  {
+    if (centralWidget_.get() == NULL)
+    {
+      return;
+    }
+
+    lastMouseX_ = x;
+    lastMouseY_ = y;
+
+    bool repaint = false;
+    
+    if (mouseTracker_.get() != NULL)
+    {
+      mouseTracker_->MouseMove(x, y, displayTouches);
+      repaint = true;
+    }
+    else
+    {
+      repaint = centralWidget_->HasRenderMouseOver();
+    }
+
+    if (repaint)
+    {
+      // The scene must be repainted, notify the observers
+      NotifyContentChanged();
+    }
+  }
+
+
+  void WidgetViewport::MouseEnter()
+  {
+    isMouseOver_ = true;
+    NotifyContentChanged();
+  }
+
+
+  void WidgetViewport::MouseLeave()
+  {
+    isMouseOver_ = false;
+
+    if (mouseTracker_.get() != NULL)
+    {
+      mouseTracker_->MouseUp();
+      mouseTracker_.reset(NULL);
+    }
+
+    NotifyContentChanged();
+  }
+
+
+  void WidgetViewport::MouseWheel(OrthancStone::MouseWheelDirection direction,
+                                  int x,
+                                  int y,
+                                  OrthancStone::KeyboardModifiers modifiers)
+  {
+    if (centralWidget_.get() != NULL &&
+        mouseTracker_.get() == NULL)
+    {
+      centralWidget_->MouseWheel(direction, x, y, modifiers);
+    }
+  }
+
+
+  void WidgetViewport::KeyPressed(OrthancStone::KeyboardKeys key,
+                                  char keyChar,
+                                  OrthancStone::KeyboardModifiers modifiers)
+  {
+    if (centralWidget_.get() != NULL &&
+        mouseTracker_.get() == NULL)
+    {
+      centralWidget_->KeyPressed(key, keyChar, modifiers);
+    }
+  }
+
+
+  bool WidgetViewport::HasAnimation()
+  {
+    if (centralWidget_.get() != NULL)
+    {
+      return centralWidget_->HasAnimation();
+    }
+    else
+    {
+      return false;
+    }
+  }
+   
+
+  void WidgetViewport::DoAnimation()
+  {
+    if (centralWidget_.get() != NULL)
+    {
+      centralWidget_->DoAnimation();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Viewport/WidgetViewport.h	Tue May 21 14:27:35 2019 +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-2019 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 "IViewport.h"
+#include "../Widgets/IWidget.h"
+
+#include <memory>
+
+namespace Deprecated
+{
+  class WidgetViewport : public IViewport
+  {
+  private:
+    std::auto_ptr<IWidget>        centralWidget_;
+    IStatusBar*                   statusBar_;
+    std::auto_ptr<IMouseTracker>  mouseTracker_;
+    bool                          isMouseOver_;
+    int                           lastMouseX_;
+    int                           lastMouseY_;
+    OrthancStone::CairoSurface    background_;
+    bool                          backgroundChanged_;
+
+  public:
+    WidgetViewport(OrthancStone::MessageBroker& broker);
+
+    virtual void FitContent();
+
+    virtual void SetStatusBar(IStatusBar& statusBar);
+
+    IWidget& SetCentralWidget(IWidget* widget);  // Takes ownership
+
+    virtual void NotifyBackgroundChanged();
+
+    virtual void SetSize(unsigned int width,
+                         unsigned int height);
+
+    virtual bool Render(Orthanc::ImageAccessor& surface);
+
+    virtual void MouseDown(OrthancStone::MouseButton button,
+                           int x,
+                           int y,
+                           OrthancStone::KeyboardModifiers modifiers,
+                           const std::vector<Touch>& displayTouches);
+
+    virtual void MouseUp();
+
+    virtual void MouseMove(int x, 
+                           int y,
+                           const std::vector<Touch>& displayTouches);
+
+    virtual void MouseEnter();
+
+    virtual void MouseLeave();
+
+    virtual void TouchStart(const std::vector<Touch>& touches);
+    
+    virtual void TouchMove(const std::vector<Touch>& touches);
+    
+    virtual void TouchEnd(const std::vector<Touch>& touches);
+
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                            int x,
+                            int y,
+                            OrthancStone::KeyboardModifiers modifiers);
+
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers);
+
+    virtual bool HasAnimation();
+
+    virtual void DoAnimation();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Volumes/ISlicedVolume.h	Tue May 21 14:27:35 2019 +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-2019 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 "../../Messages/IObservable.h"
+#include "../Toolbox/Slice.h"
+
+namespace Deprecated
+{
+  class ISlicedVolume : public OrthancStone::IObservable
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, ISlicedVolume);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, ISlicedVolume);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, ISlicedVolume);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeReadyMessage, ISlicedVolume);
+
+
+    class SliceContentChangedMessage : public OrthancStone::OriginMessage<ISlicedVolume>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      size_t        sliceIndex_;
+      const Slice&  slice_;
+      
+    public:
+      SliceContentChangedMessage(ISlicedVolume& origin,
+                                 size_t sliceIndex,
+                                 const Slice& slice) :
+        OriginMessage(origin),
+        sliceIndex_(sliceIndex),
+        slice_(slice)
+      {
+      }
+
+      size_t GetSliceIndex() const
+      {
+        return sliceIndex_;
+      }
+
+      const Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+
+    ISlicedVolume(OrthancStone::MessageBroker& broker) :
+      IObservable(broker)
+    {
+    }
+    
+    virtual size_t GetSliceCount() const = 0;
+
+    virtual const Slice& GetSlice(size_t slice) const = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Volumes/IVolumeLoader.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,40 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../Messages/IObservable.h"
+
+namespace Deprecated
+{
+  class IVolumeLoader : public OrthancStone::IObservable
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader);
+
+    IVolumeLoader(OrthancStone::MessageBroker& broker) :
+      IObservable(broker)
+    {
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Volumes/StructureSetLoader.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,116 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "StructureSetLoader.h"
+
+#include "../../Toolbox/MessagingToolbox.h"
+
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker,
+                                         OrthancApiClient& orthanc) :
+    IVolumeLoader(broker),
+    IObserver(broker),
+    orthanc_(orthanc)
+  {
+  }
+  
+
+  void StructureSetLoader::OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
+
+    Orthanc::DicomMap slice;
+    OrthancStone::MessagingToolbox::ConvertDataset(slice, dataset);
+    structureSet_->AddReferencedSlice(slice);
+
+    BroadcastMessage(ContentChangedMessage(*this));
+  }
+  
+
+  void StructureSetLoader::OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
+    structureSet_.reset(new OrthancStone::DicomStructureSet(dataset));
+
+    std::set<std::string> instances;
+    structureSet_->GetReferencedInstances(instances);
+
+    for (std::set<std::string>::const_iterator it = instances.begin();
+         it != instances.end(); ++it)
+    {
+      orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it,
+                                         new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted));
+    }
+
+    BroadcastMessage(GeometryReadyMessage(*this));
+  }
+
+  
+  void StructureSetLoader::OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message)
+  {
+    const Json::Value& lookup = message.GetJson();
+
+    if (lookup.type() != Json::arrayValue ||
+        lookup.size() != 1 ||
+        !lookup[0].isMember("Type") ||
+        !lookup[0].isMember("Path") ||
+        lookup[0]["Type"].type() != Json::stringValue ||
+        lookup[0]["ID"].type() != Json::stringValue ||
+        lookup[0]["Type"].asString() != "Instance")
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    }
+
+    const std::string& instance = lookup[0]["ID"].asString();
+    orthanc_.GetJsonAsync("/instances/" + instance + "/tags",
+                          new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnReferencedSliceLoaded));
+  }
+
+  
+  void StructureSetLoader::ScheduleLoadInstance(const std::string& instance)
+  {
+    if (structureSet_.get() != NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050",
+                            new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnStructureSetLoaded));
+    }
+  }
+
+
+  OrthancStone::DicomStructureSet& StructureSetLoader::GetStructureSet()
+  {
+    if (structureSet_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      return *structureSet_;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Volumes/StructureSetLoader.h	Tue May 21 14:27:35 2019 +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-2019 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 "../../Toolbox/DicomStructureSet.h"
+#include "../Toolbox/OrthancApiClient.h"
+#include "IVolumeLoader.h"
+
+namespace Deprecated
+{
+  class StructureSetLoader :
+    public IVolumeLoader,
+    public OrthancStone::IObserver
+  {
+  private:
+    OrthancApiClient&                 orthanc_;
+    std::auto_ptr<OrthancStone::DicomStructureSet>  structureSet_;
+
+    void OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+    void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message);
+
+  public:
+    StructureSetLoader(OrthancStone::MessageBroker& broker,
+                       OrthancApiClient& orthanc);
+
+    void ScheduleLoadInstance(const std::string& instance);
+
+    bool HasStructureSet() const
+    {
+      return structureSet_.get() != NULL;
+    }
+
+    OrthancStone::DicomStructureSet& GetStructureSet();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/CairoWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,101 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "CairoWidget.h"
+
+#include <Core/Images/ImageProcessing.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  static bool IsAligned(const Orthanc::ImageAccessor& target)
+  {
+    // TODO
+    return true;
+  }
+
+  CairoWidget::CairoWidget(const std::string& name) :
+    WidgetBase(name)
+  {
+  }
+
+  void CairoWidget::SetSize(unsigned int width,
+                            unsigned int height)
+  {
+    surface_.SetSize(width, height, false /* no alpha */);
+  }
+  
+
+  bool CairoWidget::Render(Orthanc::ImageAccessor& target)
+  {
+    // Don't call the base class here, as
+    // "ClearBackgroundCairo()" is a faster alternative
+
+    if (IsAligned(target))
+    {
+      OrthancStone::CairoSurface surface(target, false /* no alpha */);
+      OrthancStone::CairoContext context(surface);
+      ClearBackgroundCairo(context);
+      return RenderCairo(context);
+    }
+    else
+    {
+      OrthancStone::CairoContext context(surface_);
+      ClearBackgroundCairo(context);
+
+      if (RenderCairo(context))
+      {
+        Orthanc::ImageAccessor surface;
+        surface_.GetReadOnlyAccessor(surface);
+        Orthanc::ImageProcessing::Copy(target, surface);
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+  }
+
+
+  void CairoWidget::RenderMouseOver(Orthanc::ImageAccessor& target,
+                                    int x,
+                                    int y)
+  {
+    if (IsAligned(target))
+    {
+      OrthancStone::CairoSurface surface(target, false /* no alpha */);
+      OrthancStone::CairoContext context(surface);
+      RenderMouseOverCairo(context, x, y);
+    }
+    else
+    {
+      Orthanc::ImageAccessor accessor;
+      surface_.GetWriteableAccessor(accessor);
+      Orthanc::ImageProcessing::Copy(accessor, target);
+
+      OrthancStone::CairoContext context(surface_);
+      RenderMouseOverCairo(context, x, y);
+
+      Orthanc::ImageProcessing::Copy(target, accessor);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/CairoWidget.h	Tue May 21 14:27:35 2019 +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-2019 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 "WidgetBase.h"
+
+namespace Deprecated
+{
+  class CairoWidget : public WidgetBase
+  {
+  private:
+    OrthancStone::CairoSurface   surface_;
+
+  protected:
+    virtual bool RenderCairo(OrthancStone::CairoContext& context) = 0;
+    
+    virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
+                                      int x,
+                                      int y) = 0;
+    
+  public:
+    CairoWidget(const std::string& name);
+
+    virtual void SetSize(unsigned int width,
+                         unsigned int height);
+
+    virtual bool Render(Orthanc::ImageAccessor& target);
+
+    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
+                                 int x,
+                                 int y);  
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/EmptyWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,41 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "EmptyWidget.h"
+
+#include <Core/Images/ImageProcessing.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  bool EmptyWidget::Render(Orthanc::ImageAccessor& surface)
+  {
+    // Note: This call is slow
+    Orthanc::ImageProcessing::Set(surface, red_, green_, blue_, 255);
+    return true;
+  }
+
+
+  void EmptyWidget::DoAnimation()
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/EmptyWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,116 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IWidget.h"
+
+namespace Deprecated
+{
+  /**
+   * This is a test widget that simply fills its surface with an
+   * uniform color.
+   **/
+  class EmptyWidget : public IWidget
+  {
+  private:
+    uint8_t  red_;
+    uint8_t  green_;
+    uint8_t  blue_;
+
+  public:
+    EmptyWidget(uint8_t red,
+                uint8_t green,
+                uint8_t blue) :
+      red_(red),
+      green_(green),
+      blue_(blue)
+    {
+    }
+
+    virtual void FitContent()
+    {
+    }
+
+    virtual void SetParent(IWidget& widget)
+    {
+    }
+
+    virtual void SetViewport(WidgetViewport& viewport)
+    {
+    }
+
+    virtual void NotifyContentChanged()
+    {
+    }
+
+    virtual void SetStatusBar(IStatusBar& statusBar)
+    {
+    }
+
+    virtual void SetSize(unsigned int width,
+                         unsigned int height)
+    {
+    }
+
+    virtual bool Render(Orthanc::ImageAccessor& surface);
+
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
+                                              int x,
+                                              int y,
+                                              OrthancStone::KeyboardModifiers modifiers,
+                                              const std::vector<Touch>& touches)
+    {
+      return NULL;
+    }
+
+    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
+                                 int x,
+                                 int y)
+    {
+    }
+
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                            int x,
+                            int y,
+                            OrthancStone::KeyboardModifiers modifiers)
+    {
+    }
+
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers)
+    {
+    }
+
+    virtual bool HasAnimation() const
+    {
+      return false;
+    }
+
+    virtual void DoAnimation();
+
+    virtual bool HasRenderMouseOver()
+    {
+      return false;
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/IWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,81 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "../../StoneEnumerations.h"
+#include "../Viewport/IMouseTracker.h"
+#include "../Viewport/IStatusBar.h"
+
+namespace Deprecated
+{
+  class WidgetViewport;  // Forward declaration
+  
+  class IWidget : public boost::noncopyable
+  {
+  public:
+    virtual ~IWidget()
+    {
+    }
+
+    virtual void FitContent() = 0;
+
+    virtual void SetParent(IWidget& parent) = 0;
+    
+    virtual void SetViewport(WidgetViewport& viewport) = 0;
+
+    virtual void SetStatusBar(IStatusBar& statusBar) = 0;
+
+    virtual void SetSize(unsigned int width, 
+                         unsigned int height) = 0;
+ 
+    virtual bool Render(Orthanc::ImageAccessor& surface) = 0;
+
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
+                                              int x,
+                                              int y,
+                                              OrthancStone::KeyboardModifiers modifiers,
+                                              const std::vector<Touch>& touches) = 0;
+
+    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
+                                 int x,
+                                 int y) = 0;
+
+    virtual bool HasRenderMouseOver() = 0;
+
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                            int x,
+                            int y,
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
+
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers) = 0;
+
+    virtual bool HasAnimation() const = 0;
+
+    virtual void DoAnimation() = 0;
+
+    // Subclasses can call this method to signal the display of the
+    // widget must be refreshed
+    virtual void NotifyContentChanged() = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/IWorldSceneInteractor.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,70 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IWorldSceneMouseTracker.h"
+
+#include "../Toolbox/ViewportGeometry.h"
+#include "../../StoneEnumerations.h"
+#include "../Viewport/IStatusBar.h"
+
+namespace Deprecated
+{
+    class WorldSceneWidget;
+
+    class IWorldSceneInteractor : public boost::noncopyable
+    {
+    public:
+        virtual ~IWorldSceneInteractor()
+        {
+        }
+
+        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                            const ViewportGeometry& view,
+                                                            OrthancStone::MouseButton button,
+                                                            OrthancStone::KeyboardModifiers modifiers,
+                                                            int viewportX,
+                                                            int viewportY,
+                                                            double x,
+                                                            double y,
+                                                            IStatusBar* statusBar,
+                                                            const std::vector<Touch>& touches) = 0;
+
+        virtual void MouseOver(OrthancStone::CairoContext& context,
+                               WorldSceneWidget& widget,
+                               const ViewportGeometry& view,
+                               double x,
+                               double y,
+                               IStatusBar* statusBar) = 0;
+
+        virtual void MouseWheel(WorldSceneWidget& widget,
+                                OrthancStone::MouseWheelDirection direction,
+                                OrthancStone::KeyboardModifiers modifiers,
+                                IStatusBar* statusBar) = 0;
+
+        virtual void KeyPressed(WorldSceneWidget& widget,
+                                OrthancStone::KeyboardKeys key,
+                                char keyChar,
+                                OrthancStone::KeyboardModifiers modifiers,
+                                IStatusBar* statusBar) = 0;
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/IWorldSceneMouseTracker.h	Tue May 21 14:27:35 2019 +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-2019 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 "../../Viewport/CairoContext.h"
+#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition
+
+namespace Deprecated
+{
+
+  // this is tracking a mouse in scene coordinates/mm unlike
+  // the IMouseTracker that is tracking a mouse
+  // in screen coordinates/pixels.
+  class IWorldSceneMouseTracker : public boost::noncopyable
+  {
+  public:
+    virtual ~IWorldSceneMouseTracker()
+    {
+    }
+
+    virtual bool HasRender() const = 0;
+
+    virtual void Render(OrthancStone::CairoContext& context,
+                        double zoom) = 0;
+
+    virtual void MouseUp() = 0;
+
+    virtual void MouseMove(int displayX,
+                           int displayY,
+                           double sceneX,
+                           double sceneY,
+                           const std::vector<Touch>& displayTouches,
+                           const std::vector<Touch>& sceneTouches) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/LayoutWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,503 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "LayoutWidget.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/math/special_functions/round.hpp>
+
+namespace Deprecated
+{
+  class LayoutWidget::LayoutMouseTracker : public IMouseTracker
+  {
+  private:
+    std::auto_ptr<IMouseTracker>   tracker_;
+    int                            left_;
+    int                            top_;
+    unsigned int                   width_;
+    unsigned int                   height_;
+
+  public:
+    LayoutMouseTracker(IMouseTracker* tracker,
+                       int left,
+                       int top,
+                       unsigned int width,
+                       unsigned int height) :
+      tracker_(tracker),
+      left_(left),
+      top_(top),
+      width_(width),
+      height_(height)
+    {
+      if (tracker == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+
+    virtual void Render(Orthanc::ImageAccessor& surface)
+    {
+      Orthanc::ImageAccessor accessor;
+      surface.GetRegion(accessor, left_, top_, width_, height_);
+      tracker_->Render(accessor);
+    }
+
+    virtual void MouseUp()
+    {
+      tracker_->MouseUp();
+    }
+
+    virtual void MouseMove(int x, 
+                           int y,
+                           const std::vector<Touch>& displayTouches)
+    {
+      std::vector<Touch> relativeTouches;
+      for (size_t t = 0; t < displayTouches.size(); t++)
+      {
+        relativeTouches.push_back(Touch(displayTouches[t].x - left_, displayTouches[t].y - top_));
+      }
+
+      tracker_->MouseMove(x - left_, y - top_, relativeTouches);
+    }
+  };
+
+
+  class LayoutWidget::ChildWidget : public boost::noncopyable
+  {
+  private:
+    std::auto_ptr<IWidget>  widget_;
+    int                     left_;
+    int                     top_;
+    unsigned int            width_;
+    unsigned int            height_;
+
+  public:
+    ChildWidget(IWidget* widget) :
+      widget_(widget)
+    {
+      assert(widget != NULL);
+      SetEmpty();
+    }
+
+    void DoAnimation()
+    {
+      if (widget_->HasAnimation())
+      {
+        widget_->DoAnimation();
+      }
+    }
+
+    IWidget& GetWidget() const
+    {
+      return *widget_;
+    }
+
+    void SetRectangle(unsigned int left, 
+                      unsigned int top,
+                      unsigned int width,
+                      unsigned int height)
+    {
+      left_ = left;
+      top_ = top;
+      width_ = width;
+      height_ = height;
+
+      widget_->SetSize(width, height);
+    }
+
+    void SetEmpty()
+    {
+      SetRectangle(0, 0, 0, 0);
+    }
+
+    bool Contains(int x, 
+                  int y) const
+    {
+      return (x >= left_ && 
+              y >= top_ &&
+              x < left_ + static_cast<int>(width_) &&
+              y < top_ + static_cast<int>(height_));
+    }      
+
+    bool Render(Orthanc::ImageAccessor& target)
+    {
+      if (width_ == 0 ||
+          height_ == 0)
+      {
+        return true;
+      }
+      else 
+      {
+        Orthanc::ImageAccessor accessor;
+        target.GetRegion(accessor, left_, top_, width_, height_);
+        return widget_->Render(accessor);
+      }
+    }
+
+    IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
+                                      int x,
+                                      int y,
+                                      OrthancStone::KeyboardModifiers modifiers,
+                                      const std::vector<Touch>& touches)
+    {
+      if (Contains(x, y))
+      {
+        IMouseTracker* tracker = widget_->CreateMouseTracker(button, 
+                                                             x - left_, 
+                                                             y - top_, 
+                                                             modifiers,
+                                                             touches);
+        if (tracker)
+        {
+          return new LayoutMouseTracker(tracker, left_, top_, width_, height_);
+        }
+      }
+
+      return NULL;
+    }
+
+    void RenderMouseOver(Orthanc::ImageAccessor& target,
+                         int x,
+                         int y)
+    {
+      if (Contains(x, y))
+      {
+        Orthanc::ImageAccessor accessor;
+        target.GetRegion(accessor, left_, top_, width_, height_);
+
+        widget_->RenderMouseOver(accessor, x - left_, y - top_);
+      }
+    }
+
+    void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                    int x,
+                    int y,
+                    OrthancStone::KeyboardModifiers modifiers)
+    {
+      if (Contains(x, y))
+      {
+        widget_->MouseWheel(direction, x - left_, y - top_, modifiers);
+      }
+    }
+    
+    bool HasRenderMouseOver()
+    {
+      return widget_->HasRenderMouseOver();
+    }
+  };
+
+
+  void LayoutWidget::ComputeChildrenExtents()
+  {
+    if (children_.size() == 0)
+    {
+      return;
+    }
+
+    float internal = static_cast<float>(paddingInternal_);
+
+    if (width_ <= paddingLeft_ + paddingRight_ ||
+        height_ <= paddingTop_ + paddingBottom_)
+    {
+      for (size_t i = 0; i < children_.size(); i++)
+      {
+        children_[i]->SetEmpty();          
+      }
+    }
+    else if (isHorizontal_)
+    {
+      unsigned int padding = paddingLeft_ + paddingRight_ + (static_cast<unsigned int>(children_.size()) - 1) * paddingInternal_;
+      float childWidth = ((static_cast<float>(width_) - static_cast<float>(padding)) / 
+                          static_cast<float>(children_.size()));
+        
+      for (size_t i = 0; i < children_.size(); i++)
+      {
+        float left = static_cast<float>(paddingLeft_) + static_cast<float>(i) * (childWidth + internal);
+        float right = left + childWidth;
+
+        if (left >= right)
+        {
+          children_[i]->SetEmpty();
+        }
+        else
+        {
+          children_[i]->SetRectangle(static_cast<unsigned int>(left), 
+                                     paddingTop_, 
+                                     boost::math::iround(right - left),
+                                     height_ - paddingTop_ - paddingBottom_);
+        }
+      }
+    }
+    else
+    {
+      unsigned int padding = paddingTop_ + paddingBottom_ + (static_cast<unsigned int>(children_.size()) - 1) * paddingInternal_;
+      float childHeight = ((static_cast<float>(height_) - static_cast<float>(padding)) / 
+                           static_cast<float>(children_.size()));
+        
+      for (size_t i = 0; i < children_.size(); i++)
+      {
+        float top = static_cast<float>(paddingTop_) + static_cast<float>(i) * (childHeight + internal);
+        float bottom = top + childHeight;
+
+        if (top >= bottom)
+        {
+          children_[i]->SetEmpty();
+        }
+        else
+        {
+          children_[i]->SetRectangle(paddingTop_, 
+                                     static_cast<unsigned int>(top), 
+                                     width_ - paddingLeft_ - paddingRight_,
+                                     boost::math::iround(bottom - top));
+        }
+      }
+    }
+
+    NotifyContentChanged(*this);
+  }
+
+
+  LayoutWidget::LayoutWidget(const std::string& name) :
+    WidgetBase(name),
+    isHorizontal_(true),
+    width_(0),
+    height_(0),
+    paddingLeft_(0),
+    paddingTop_(0),
+    paddingRight_(0),
+    paddingBottom_(0),
+    paddingInternal_(0)
+  {
+  }
+
+
+  LayoutWidget::~LayoutWidget()
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      delete children_[i];
+    }
+  }
+
+
+  void LayoutWidget::FitContent()
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      children_[i]->GetWidget().FitContent();
+    }
+  }
+  
+
+  void LayoutWidget::NotifyContentChanged(const IWidget& widget)
+  {
+    // One of the children has changed
+    WidgetBase::NotifyContentChanged();
+  }
+
+
+  void LayoutWidget::SetHorizontal()
+  {
+    isHorizontal_ = true;
+    ComputeChildrenExtents();
+  }
+
+
+  void LayoutWidget::SetVertical()
+  {
+    isHorizontal_ = false;
+    ComputeChildrenExtents();
+  }
+
+
+  void LayoutWidget::SetPadding(unsigned int left,
+                                unsigned int top,
+                                unsigned int right,
+                                unsigned int bottom,
+                                unsigned int spacing)
+  {
+    paddingLeft_ = left;
+    paddingTop_ = top;
+    paddingRight_ = right;
+    paddingBottom_ = bottom;
+    paddingInternal_ = spacing;
+  }
+    
+
+  void LayoutWidget::SetPadding(unsigned int padding)
+  {
+    paddingLeft_ = padding;
+    paddingTop_ = padding;
+    paddingRight_ = padding;
+    paddingBottom_ = padding;
+    paddingInternal_ = padding;
+  }
+
+
+  IWidget& LayoutWidget::AddWidget(IWidget* widget)  // Takes ownership
+  {
+    if (widget == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    if (GetStatusBar() != NULL)
+    {
+      widget->SetStatusBar(*GetStatusBar());
+    }
+
+    children_.push_back(new ChildWidget(widget));
+    widget->SetParent(*this);
+
+    ComputeChildrenExtents();
+
+    if (widget->HasAnimation())
+    {
+      hasAnimation_ = true;
+    }
+
+    return *widget;
+  }
+
+
+  void LayoutWidget::SetStatusBar(IStatusBar& statusBar)
+  {
+    WidgetBase::SetStatusBar(statusBar);
+
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      children_[i]->GetWidget().SetStatusBar(statusBar);
+    }
+  }
+
+
+  void LayoutWidget::SetSize(unsigned int width,
+                             unsigned int height)
+  {
+    width_ = width;
+    height_ = height;
+    ComputeChildrenExtents();
+  }
+
+
+  bool LayoutWidget::Render(Orthanc::ImageAccessor& surface)
+  {
+    if (!WidgetBase::Render(surface))
+    {
+      return false;
+    }
+
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      if (!children_[i]->Render(surface))
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+    
+  IMouseTracker* LayoutWidget::CreateMouseTracker(OrthancStone::MouseButton button,
+                                                  int x,
+                                                  int y,
+                                                  OrthancStone::KeyboardModifiers modifiers,
+                                                  const std::vector<Touch>& touches)
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      IMouseTracker* tracker = children_[i]->CreateMouseTracker(button, x, y, modifiers, touches);
+      if (tracker != NULL)
+      {
+        return tracker;
+      }
+    }
+
+    return NULL;
+  }
+
+
+  void LayoutWidget::RenderMouseOver(Orthanc::ImageAccessor& target,
+                                     int x,
+                                     int y)
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      children_[i]->RenderMouseOver(target, x, y);
+    }
+  }
+
+
+  void LayoutWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
+                                int x,
+                                int y,
+                                OrthancStone::KeyboardModifiers modifiers)
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      children_[i]->MouseWheel(direction, x, y, modifiers);
+    }
+  }
+
+
+  void LayoutWidget::KeyPressed(OrthancStone::KeyboardKeys key,
+                                char keyChar,
+                                OrthancStone::KeyboardModifiers modifiers)
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      children_[i]->GetWidget().KeyPressed(key, keyChar, modifiers);
+    }
+  }
+
+  
+  void LayoutWidget::DoAnimation()
+  {
+    if (hasAnimation_)
+    {
+      for (size_t i = 0; i < children_.size(); i++)
+      {
+        children_[i]->DoAnimation();
+      }
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+  }
+
+
+  bool LayoutWidget::HasRenderMouseOver()
+  {
+    for (size_t i = 0; i < children_.size(); i++)
+    {
+      if (children_[i]->HasRenderMouseOver())
+      {
+        return true;
+      }
+    }
+
+    return false;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/LayoutWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,134 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WidgetBase.h"
+
+#include <vector>
+#include <memory>
+
+namespace Deprecated
+{
+  class LayoutWidget : public WidgetBase
+  {
+  private:
+    class LayoutMouseTracker;
+    class ChildWidget;
+
+    std::vector<ChildWidget*>     children_;
+    bool                          isHorizontal_;
+    unsigned int                  width_;
+    unsigned int                  height_;
+    std::auto_ptr<IMouseTracker>  mouseTracker_;
+    unsigned int                  paddingLeft_;
+    unsigned int                  paddingTop_;
+    unsigned int                  paddingRight_;
+    unsigned int                  paddingBottom_;
+    unsigned int                  paddingInternal_;
+    bool                          hasAnimation_;
+
+    void ComputeChildrenExtents();
+
+  public:
+    LayoutWidget(const std::string& name);
+
+    virtual ~LayoutWidget();
+
+    virtual void FitContent();
+
+    virtual void NotifyContentChanged(const IWidget& widget);
+
+    void SetHorizontal();
+
+    void SetVertical();
+
+    void SetPadding(unsigned int left,
+                    unsigned int top,
+                    unsigned int right,
+                    unsigned int bottom,
+                    unsigned int spacing);
+    
+    void SetPadding(unsigned int padding);
+
+    unsigned int GetPaddingLeft() const
+    {
+      return paddingLeft_;
+    }
+
+    unsigned int GetPaddingTop() const
+    {
+      return paddingTop_;
+    }
+
+    unsigned int GetPaddingRight() const
+    {
+      return paddingRight_;
+    }
+
+    unsigned int GetPaddingBottom() const
+    {
+      return paddingBottom_;
+    }
+
+    unsigned int GetPaddingInternal() const
+    {
+      return paddingInternal_;
+    }
+
+    IWidget& AddWidget(IWidget* widget);  // Takes ownership
+
+    virtual void SetStatusBar(IStatusBar& statusBar);
+
+    virtual void SetSize(unsigned int width,
+                         unsigned int height);
+
+    virtual bool Render(Orthanc::ImageAccessor& surface);
+    
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
+                                              int x,
+                                              int y,
+                                              OrthancStone::KeyboardModifiers modifiers,
+                                              const std::vector<Touch>& touches);
+
+    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
+                                 int x,
+                                 int y);
+
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                            int x,
+                            int y,
+                            OrthancStone::KeyboardModifiers modifiers);
+
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers);
+
+    virtual bool HasAnimation() const
+    {
+      return hasAnimation_;
+    }
+
+    virtual void DoAnimation();
+
+    virtual bool HasRenderMouseOver();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/PanMouseTracker.cpp	Tue May 21 14:27:35 2019 +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-2019 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 "PanMouseTracker.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  PanMouseTracker::PanMouseTracker(WorldSceneWidget& that,
+                                   int x,
+                                   int y) :
+    that_(that)
+  {
+    that.GetView().GetPan(originalPanX_, originalPanY_);
+    that.GetView().MapPixelCenterToScene(downX_, downY_, x, y);
+  }
+    
+
+  void PanMouseTracker::Render(OrthancStone::CairoContext& context,
+                               double zoom)
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+  }
+
+
+  void PanMouseTracker::MouseMove(int displayX,
+                                  int displayY,
+                                  double x,
+                                  double y,
+                                  const std::vector<Touch>& displayTouches,
+                                  const std::vector<Touch>& sceneTouches)
+  {
+    ViewportGeometry view = that_.GetView();
+    view.SetPan(originalPanX_ + (x - downX_) * view.GetZoom(),
+                originalPanY_ + (y - downY_) * view.GetZoom());
+    that_.SetView(view);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/PanMouseTracker.h	Tue May 21 14:27:35 2019 +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-2019 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 "WorldSceneWidget.h"
+
+namespace Deprecated
+{
+  class PanMouseTracker : public IWorldSceneMouseTracker
+  {
+  private:
+    WorldSceneWidget&  that_;
+    double             originalPanX_;
+    double             originalPanY_;
+    double             downX_;
+    double             downY_;
+    
+  public:
+    PanMouseTracker(WorldSceneWidget& that,
+                    int x,
+                    int y);
+    
+    virtual bool HasRender() const
+    {
+      return false;
+    }
+
+    virtual void MouseUp()
+    {
+    }
+
+    virtual void Render(OrthancStone::CairoContext& context,
+                        double zoom);
+
+    virtual void MouseMove(int displayX,
+                           int displayY,
+                           double x,
+                           double y,
+                           const std::vector<Touch>& displayTouches,
+                           const std::vector<Touch>& sceneTouches);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/PanZoomMouseTracker.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,137 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "PanZoomMouseTracker.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+#include <math.h>
+
+namespace Deprecated
+{
+  Touch GetCenter(const std::vector<Touch>& touches)
+  {
+    return Touch((touches[0].x + touches[1].x) / 2.0f, (touches[0].y + touches[1].y) / 2.0f);
+  }
+
+  double GetDistance(const std::vector<Touch>& touches)
+  {
+    float dx = touches[0].x - touches[1].x;
+    float dy = touches[0].y - touches[1].y;
+    return sqrt((double)(dx * dx) + (double)(dy * dy));
+  }
+
+
+  PanZoomMouseTracker::PanZoomMouseTracker(WorldSceneWidget& that,
+                                           const std::vector<Touch>& startTouches)
+    : that_(that),
+      originalZoom_(that.GetView().GetZoom())
+  {
+    that.GetView().GetPan(originalPanX_, originalPanY_);
+    that.GetView().MapPixelCenterToScene(originalSceneTouches_, startTouches);
+
+    originalDisplayCenter_ = GetCenter(startTouches);
+    originalSceneCenter_ = GetCenter(originalSceneTouches_);
+    originalDisplayDistanceBetweenTouches_ = GetDistance(startTouches);
+
+//    printf("original Pan %f %f\n", originalPanX_, originalPanY_);
+//    printf("original Zoom %f \n", originalZoom_);
+//    printf("original distance %f \n", (float)originalDisplayDistanceBetweenTouches_);
+//    printf("original display touches 0 %f %f\n", startTouches[0].x, startTouches[0].y);
+//    printf("original display touches 1 %f %f\n", startTouches[1].x, startTouches[1].y);
+//    printf("original Scene center %f %f\n", originalSceneCenter_.x, originalSceneCenter_.y);
+
+    unsigned int height = that.GetView().GetDisplayHeight();
+
+    if (height <= 3)
+    {
+      idle_ = true;
+      LOG(WARNING) << "image is too small to zoom (current height = " << height << ")";
+    }
+    else
+    {
+      idle_ = false;
+      normalization_ = 1.0 / static_cast<double>(height - 1);
+    }
+
+  }
+
+
+  void PanZoomMouseTracker::Render(OrthancStone::CairoContext& context,
+                                   double zoom)
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+  }
+
+
+  void PanZoomMouseTracker::MouseMove(int displayX,
+                                      int displayY,
+                                      double x,
+                                      double y,
+                                      const std::vector<Touch>& displayTouches,
+                                      const std::vector<Touch>& sceneTouches)
+  {
+    ViewportGeometry view = that_.GetView();
+
+//    printf("Display touches 0 %f %f\n", displayTouches[0].x, displayTouches[0].y);
+//    printf("Display touches 1 %f %f\n", displayTouches[1].x, displayTouches[1].y);
+//    printf("Scene touches 0 %f %f\n", sceneTouches[0].x, sceneTouches[0].y);
+//    printf("Scene touches 1 %f %f\n", sceneTouches[1].x, sceneTouches[1].y);
+
+//    printf("zoom = %f\n", view.GetZoom());
+    Touch currentSceneCenter = GetCenter(sceneTouches);
+    double panX = originalPanX_ + (currentSceneCenter.x - originalSceneCenter_.x) * view.GetZoom();
+    double panY = originalPanY_ + (currentSceneCenter.y - originalSceneCenter_.y) * view.GetZoom();
+
+    view.SetPan(panX, panY);
+
+    static const double MIN_ZOOM = -4;
+    static const double MAX_ZOOM = 4;
+
+    if (!idle_)
+    {
+      double currentDistanceBetweenTouches = GetDistance(displayTouches);
+
+      double dy = static_cast<double>(currentDistanceBetweenTouches - originalDisplayDistanceBetweenTouches_) * normalization_;  // In the range [-1,1]
+      double z;
+
+      // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
+      if (dy < -1.0)
+      {
+        z = MIN_ZOOM;
+      }
+      else if (dy > 1.0)
+      {
+        z = MAX_ZOOM;
+      }
+      else
+      {
+        z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0;
+      }
+
+      z = pow(2.0, z);
+
+      view.SetZoom(z * originalZoom_);
+    }
+
+    that_.SetView(view);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/PanZoomMouseTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,65 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
+
+namespace Deprecated
+{
+  class PanZoomMouseTracker : public IWorldSceneMouseTracker
+  {
+  private:
+    WorldSceneWidget&  that_;
+    std::vector<Touch> originalSceneTouches_;
+    Touch              originalSceneCenter_;
+    Touch              originalDisplayCenter_;
+    double             originalPanX_;
+    double             originalPanY_;
+    double             originalZoom_;
+    double             originalDisplayDistanceBetweenTouches_;
+    bool               idle_;
+    double             normalization_;
+
+  public:
+    PanZoomMouseTracker(WorldSceneWidget& that,
+                        const std::vector<Touch>& startTouches);
+    
+    virtual bool HasRender() const
+    {
+      return false;
+    }
+
+    virtual void MouseUp()
+    {
+    }
+
+    virtual void Render(OrthancStone::CairoContext& context,
+                        double zoom);
+
+    virtual void MouseMove(int displayX,
+                           int displayY,
+                           double x,
+                           double y,
+                           const std::vector<Touch>& displayTouches,
+                           const std::vector<Touch>& sceneTouches);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/SliceViewerWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,654 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "SliceViewerWidget.h"
+
+#include "../Layers/SliceOutlineRenderer.h"
+#include "../../Toolbox/GeometryToolbox.h"
+#include "../Layers/FrameRenderer.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <boost/math/constants/constants.hpp>
+
+
+static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits<double>::epsilon();
+
+namespace Deprecated
+{
+  class SliceViewerWidget::Scene : public boost::noncopyable
+  {
+  private:
+    OrthancStone::CoordinateSystem3D            plane_;
+    double                        thickness_;
+    size_t                        countMissing_;
+    std::vector<ILayerRenderer*>  renderers_;
+
+  public:
+    void DeleteLayer(size_t index)
+    {
+      if (index >= renderers_.size())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      }
+
+      assert(countMissing_ <= renderers_.size());
+
+      if (renderers_[index] != NULL)
+      {
+        assert(countMissing_ < renderers_.size());
+        delete renderers_[index];
+        renderers_[index] = NULL;
+        countMissing_++;
+      }
+    }
+
+    Scene(const OrthancStone::CoordinateSystem3D& plane,
+          double thickness,
+          size_t countLayers) :
+      plane_(plane),
+      thickness_(thickness),
+      countMissing_(countLayers),
+      renderers_(countLayers, NULL)
+    {
+      if (thickness <= 0)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      }
+    }
+
+    ~Scene()
+    {
+      for (size_t i = 0; i < renderers_.size(); i++)
+      {
+        DeleteLayer(i);
+      }
+    }
+
+    void SetLayer(size_t index,
+                  ILayerRenderer* renderer)  // Takes ownership
+    {
+      if (renderer == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+
+      DeleteLayer(index);
+
+      renderers_[index] = renderer;
+      countMissing_--;
+    }
+
+    const OrthancStone::CoordinateSystem3D& GetPlane() const
+    {
+      return plane_;
+    }
+
+    bool HasRenderer(size_t index)
+    {
+      return renderers_[index] != NULL;
+    }
+
+    bool IsComplete() const
+    {
+      return countMissing_ == 0;
+    }
+
+    unsigned int GetCountMissing() const
+    {
+      return static_cast<unsigned int>(countMissing_);
+    }
+
+    bool RenderScene(OrthancStone::CairoContext& context,
+                     const ViewportGeometry& view,
+                     const OrthancStone::CoordinateSystem3D& viewportPlane)
+    {
+      bool fullQuality = true;
+      cairo_t *cr = context.GetObject();
+
+      for (size_t i = 0; i < renderers_.size(); i++)
+      {
+        if (renderers_[i] != NULL)
+        {
+          const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane();
+          
+          double x0, y0, x1, y1, x2, y2;
+          viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin());
+          viewportPlane.ProjectPoint(x1, y1, framePlane.GetOrigin() + framePlane.GetAxisX());
+          viewportPlane.ProjectPoint(x2, y2, framePlane.GetOrigin() + framePlane.GetAxisY());
+
+          /**
+           * Now we solve the system of linear equations Ax + b = x', given:
+           *   A [0 ; 0] + b = [x0 ; y0]
+           *   A [1 ; 0] + b = [x1 ; y1]
+           *   A [0 ; 1] + b = [x2 ; y2]
+           * <=>
+           *   b = [x0 ; y0]
+           *   A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0]
+           *   A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0]
+           * <=>
+           *   b = [x0 ; y0]
+           *   [a11 ; a21] = [x1 - x0 ; y1 - y0]
+           *   [a12 ; a22] = [x2 - x0 ; y2 - y0]
+           **/
+
+          cairo_matrix_t transform;
+          cairo_matrix_init(&transform, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0);
+
+          cairo_save(cr);
+          cairo_transform(cr, &transform);
+          
+          if (!renderers_[i]->RenderLayer(context, view))
+          {
+            cairo_restore(cr);
+            return false;
+          }
+
+          cairo_restore(cr);
+        }
+
+        if (renderers_[i] != NULL &&
+            !renderers_[i]->IsFullQuality())
+        {
+          fullQuality = false;
+        }
+      }
+
+      if (!fullQuality)
+      {
+        double x, y;
+        view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10);
+
+        cairo_translate(cr, x, y);
+
+#if 1
+        double s = 5.0 / view.GetZoom();
+        cairo_rectangle(cr, -s, -s, 2.0 * s, 2.0 * s);
+#else
+        // TODO Drawing filled circles makes WebAssembly crash!
+        cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2.0 * boost::math::constants::pi<double>());
+#endif
+        
+        cairo_set_line_width(cr, 2.0 / view.GetZoom());
+        cairo_set_source_rgb(cr, 1, 1, 1);
+        cairo_stroke_preserve(cr);
+        cairo_set_source_rgb(cr, 1, 0, 0);
+        cairo_fill(cr);
+      }
+
+      return true;
+    }
+
+    void SetLayerStyle(size_t index,
+                       const RenderStyle& style)
+    {
+      if (renderers_[index] != NULL)
+      {
+        renderers_[index]->SetLayerStyle(style);
+      }
+    }
+
+    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
+    {
+      bool isOpposite;
+      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                               plane.GetNormal(),
+                                                               plane_.GetNormal()))
+      {
+        return false;
+      }
+      else
+      {
+        double z = (plane_.ProjectAlongNormal(plane.GetOrigin()) -
+                    plane_.ProjectAlongNormal(plane_.GetOrigin()));
+
+        if (z < 0)
+        {
+          z = -z;
+        }
+
+        return z <= thickness_;
+      }
+    }
+
+    double GetThickness() const
+    {
+      return thickness_;
+    }
+  };
+
+  
+  bool SliceViewerWidget::LookupLayer(size_t& index /* out */,
+                                      const IVolumeSlicer& layer) const
+  {
+    LayersIndex::const_iterator found = layersIndex_.find(&layer);
+
+    if (found == layersIndex_.end())
+    {
+      return false;
+    }
+    else
+    {
+      index = found->second;
+      assert(index < layers_.size() &&
+             layers_[index] == &layer);
+      return true;
+    }
+  }
+
+
+  void SliceViewerWidget::GetLayerExtent(OrthancStone::Extent2D& extent,
+                                         IVolumeSlicer& source) const
+  {
+    extent.Reset();
+
+    std::vector<OrthancStone::Vector> points;
+    if (source.GetExtent(points, plane_))
+    {
+      for (size_t i = 0; i < points.size(); i++)
+      {
+        double x, y;
+        plane_.ProjectPoint(x, y, points[i]);
+        extent.AddPoint(x, y);
+      }
+    }
+  }
+
+
+  OrthancStone::Extent2D SliceViewerWidget::GetSceneExtent()
+  {
+    OrthancStone::Extent2D sceneExtent;
+
+    for (size_t i = 0; i < layers_.size(); i++)
+    {
+      assert(layers_[i] != NULL);
+      OrthancStone::Extent2D layerExtent;
+      GetLayerExtent(layerExtent, *layers_[i]);
+
+      sceneExtent.Union(layerExtent);
+    }
+
+    return sceneExtent;
+  }
+
+  
+  bool SliceViewerWidget::RenderScene(OrthancStone::CairoContext& context,
+                                      const ViewportGeometry& view)
+  {
+    if (currentScene_.get() != NULL)
+    {
+      return currentScene_->RenderScene(context, view, plane_);
+    }
+    else
+    {
+      return true;
+    }
+  }
+
+  
+  void SliceViewerWidget::ResetPendingScene()
+  {
+    double thickness;
+    if (pendingScene_.get() == NULL)
+    {
+      thickness = 1.0;
+    }
+    else
+    {
+      thickness = pendingScene_->GetThickness();
+    }
+    
+    pendingScene_.reset(new Scene(plane_, thickness, layers_.size()));
+  }
+  
+
+  void SliceViewerWidget::UpdateLayer(size_t index,
+                                      ILayerRenderer* renderer,
+                                      const OrthancStone::CoordinateSystem3D& plane)
+  {
+    LOG(INFO) << "Updating layer " << index;
+    
+    std::auto_ptr<ILayerRenderer> tmp(renderer);
+
+    if (renderer == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    if (index >= layers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    assert(layers_.size() == styles_.size());
+    renderer->SetLayerStyle(styles_[index]);
+
+    if (currentScene_.get() != NULL &&
+        currentScene_->ContainsPlane(plane))
+    {
+      currentScene_->SetLayer(index, tmp.release());
+      NotifyContentChanged();
+    }
+    else if (pendingScene_.get() != NULL &&
+             pendingScene_->ContainsPlane(plane))
+    {
+      pendingScene_->SetLayer(index, tmp.release());
+
+      if (currentScene_.get() == NULL ||
+          !currentScene_->IsComplete() ||
+          pendingScene_->IsComplete())
+      {
+        currentScene_ = pendingScene_;
+        NotifyContentChanged();
+      }
+    }
+  }
+
+  
+  SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, 
+                                       const std::string& name) :
+    WorldSceneWidget(name),
+    IObserver(broker),
+    IObservable(broker),
+    started_(false)
+  {
+    SetBackgroundCleared(true);
+  }
+  
+  
+  SliceViewerWidget::~SliceViewerWidget()
+  {
+    for (size_t i = 0; i < layers_.size(); i++)
+    {
+      delete layers_[i];
+    }
+  }
+  
+  void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer)
+  {
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage>
+                                   (*this, &SliceViewerWidget::OnGeometryReady));
+    // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryErrorMessage>(*this, &SliceViewerWidget::...));
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::SliceContentChangedMessage>
+                                   (*this, &SliceViewerWidget::OnSliceChanged));
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage>
+                                   (*this, &SliceViewerWidget::OnContentChanged));
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage>
+                                   (*this, &SliceViewerWidget::OnLayerReady));
+    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage>
+                                   (*this, &SliceViewerWidget::OnLayerError));
+  }
+
+
+  size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer)  // Takes ownership
+  {
+    if (layer == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    size_t index = layers_.size();
+    layers_.push_back(layer);
+    styles_.push_back(RenderStyle());
+    layersIndex_[layer] = index;
+
+    ResetPendingScene();
+
+    ObserveLayer(*layer);
+
+    ResetChangedLayers();
+
+    return index;
+  }
+
+
+  void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer)  // Takes ownership
+  {
+    if (layer == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    if (index >= layers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    delete layers_[index];
+    layers_[index] = layer;
+    layersIndex_[layer] = index;
+
+    ResetPendingScene();
+
+    ObserveLayer(*layer);
+
+    InvalidateLayer(index);
+  }
+
+
+  void SliceViewerWidget::RemoveLayer(size_t index)
+  {
+    if (index >= layers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    IVolumeSlicer* previousLayer = layers_[index];
+    layersIndex_.erase(layersIndex_.find(previousLayer));
+    layers_.erase(layers_.begin() + index);
+    changedLayers_.erase(changedLayers_.begin() + index);
+    styles_.erase(styles_.begin() + index);
+
+    delete layers_[index];
+
+    currentScene_->DeleteLayer(index);
+    ResetPendingScene();
+
+    NotifyContentChanged();
+  }
+
+
+  const RenderStyle& SliceViewerWidget::GetLayerStyle(size_t layer) const
+  {
+    if (layer >= layers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    assert(layers_.size() == styles_.size());
+    return styles_[layer];
+  }
+  
+
+  void SliceViewerWidget::SetLayerStyle(size_t layer,
+                                        const RenderStyle& style)
+  {
+    if (layer >= layers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    assert(layers_.size() == styles_.size());
+    styles_[layer] = style;
+
+    if (currentScene_.get() != NULL)
+    {
+      currentScene_->SetLayerStyle(layer, style);
+    }
+
+    if (pendingScene_.get() != NULL)
+    {
+      pendingScene_->SetLayerStyle(layer, style);
+    }
+
+    NotifyContentChanged();
+  }
+  
+
+  void SliceViewerWidget::SetSlice(const OrthancStone::CoordinateSystem3D& plane)
+  {
+    LOG(INFO) << "Setting slice origin: (" << plane.GetOrigin()[0]
+              << "," << plane.GetOrigin()[1]
+              << "," << plane.GetOrigin()[2] << ")";
+    
+    Deprecated::Slice displayedSlice(plane_, THIN_SLICE_THICKNESS);
+
+    //if (!displayedSlice.ContainsPlane(slice))
+    {
+      if (currentScene_.get() == NULL ||
+          (pendingScene_.get() != NULL &&
+           pendingScene_->IsComplete()))
+      {
+        currentScene_ = pendingScene_;
+      }
+
+      plane_ = plane;
+      ResetPendingScene();
+
+      InvalidateAllLayers();   // TODO Removing this line avoid loading twice the image in WASM
+    }
+
+    BroadcastMessage(DisplayedSliceMessage(*this, displayedSlice));
+  }
+
+
+  void SliceViewerWidget::OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
+  {
+    size_t i;
+    if (LookupLayer(i, message.GetOrigin()))
+    {
+      LOG(INFO) << ": Geometry ready for layer " << i << " in " << GetName();
+
+      changedLayers_[i] = true;
+      //layers_[i]->ScheduleLayerCreation(plane_);
+    }
+    BroadcastMessage(GeometryChangedMessage(*this));
+  }
+  
+
+  void SliceViewerWidget::InvalidateAllLayers()
+  {
+    for (size_t i = 0; i < layers_.size(); i++)
+    {
+      assert(layers_[i] != NULL);
+      changedLayers_[i] = true;
+      
+      //layers_[i]->ScheduleLayerCreation(plane_);
+    }
+  }
+
+
+  void SliceViewerWidget::InvalidateLayer(size_t layer)
+  {
+    if (layer >= layers_.size())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    assert(layers_[layer] != NULL);
+    changedLayers_[layer] = true;
+
+    //layers_[layer]->ScheduleLayerCreation(plane_);
+  }
+
+
+  void SliceViewerWidget::OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message)
+  {
+    size_t index;
+    if (LookupLayer(index, message.GetOrigin()))
+    {
+      InvalidateLayer(index);
+    }
+    
+    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
+  }
+  
+
+  void SliceViewerWidget::OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message)
+  {
+    if (message.GetSlice().ContainsPlane(plane_))
+    {
+      size_t index;
+      if (LookupLayer(index, message.GetOrigin()))
+      {
+        InvalidateLayer(index);
+      }
+    }
+    
+    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
+  }
+  
+  
+  void SliceViewerWidget::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
+  {
+    size_t index;
+    if (LookupLayer(index, message.GetOrigin()))
+    {
+      LOG(INFO) << "Renderer ready for layer " << index;
+      UpdateLayer(index, message.CreateRenderer(), message.GetSlice());
+    }
+    
+    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
+  }
+
+
+  void SliceViewerWidget::OnLayerError(const IVolumeSlicer::LayerErrorMessage& message)
+  {
+    size_t index;
+    if (LookupLayer(index, message.GetOrigin()))
+    {
+      LOG(ERROR) << "Using error renderer on layer " << index;
+
+      // TODO
+      //UpdateLayer(index, new SliceOutlineRenderer(slice), slice);
+
+      BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
+    }
+  }
+
+
+  void SliceViewerWidget::ResetChangedLayers()
+  {
+    changedLayers_.resize(layers_.size());
+
+    for (size_t i = 0; i < changedLayers_.size(); i++)
+    {
+      changedLayers_[i] = false;
+    }
+  }
+
+
+  void SliceViewerWidget::DoAnimation()
+  {
+    assert(changedLayers_.size() <= layers_.size());
+    
+    for (size_t i = 0; i < changedLayers_.size(); i++)
+    {
+      if (changedLayers_[i])
+      {
+        layers_[i]->ScheduleLayerCreation(plane_);
+      }
+    }
+    
+    ResetChangedLayers();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/SliceViewerWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,155 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
+#include "../Layers/IVolumeSlicer.h"
+#include "../../Toolbox/Extent2D.h"
+#include "../../Messages/IObserver.h"
+
+#include <map>
+
+namespace Deprecated
+{
+  class SliceViewerWidget :
+    public WorldSceneWidget,
+    public OrthancStone::IObserver,
+    public OrthancStone::IObservable
+  {
+  public:
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryChangedMessage, SliceViewerWidget);
+    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, SliceViewerWidget);
+
+
+    // TODO - Use this message in ReferenceLineSource
+    class DisplayedSliceMessage : public OrthancStone::OriginMessage<SliceViewerWidget>
+    {
+      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
+      
+    private:
+      const Deprecated::Slice& slice_;
+
+    public:
+      DisplayedSliceMessage(SliceViewerWidget& origin,
+                            const Deprecated::Slice& slice) :
+        OriginMessage(origin),
+        slice_(slice)
+      {
+      }
+
+      const Deprecated::Slice& GetSlice() const
+      {
+        return slice_;
+      }
+    };
+
+  private:
+    SliceViewerWidget(const SliceViewerWidget&);
+    SliceViewerWidget& operator=(const SliceViewerWidget&);
+
+    class Scene;
+    
+    typedef std::map<const IVolumeSlicer*, size_t>  LayersIndex;
+
+    bool                         started_;
+    LayersIndex                  layersIndex_;
+    std::vector<IVolumeSlicer*>  layers_;
+    std::vector<RenderStyle>     styles_;
+    OrthancStone::CoordinateSystem3D           plane_;
+    std::auto_ptr<Scene>         currentScene_;
+    std::auto_ptr<Scene>         pendingScene_;
+    std::vector<bool>            changedLayers_;
+
+    bool LookupLayer(size_t& index /* out */,
+                     const IVolumeSlicer& layer) const;
+
+    void GetLayerExtent(OrthancStone::Extent2D& extent,
+                        IVolumeSlicer& source) const;
+
+    void OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
+
+    virtual void OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message);
+
+    virtual void OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message);
+
+    virtual void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message);
+
+    virtual void OnLayerError(const IVolumeSlicer::LayerErrorMessage& message);
+
+    void ObserveLayer(IVolumeSlicer& source);
+
+    void ResetChangedLayers();
+
+  public:
+    SliceViewerWidget(OrthancStone::MessageBroker& broker, 
+                      const std::string& name);
+
+    virtual OrthancStone::Extent2D GetSceneExtent();
+
+  protected:
+    virtual bool RenderScene(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view);
+
+    void ResetPendingScene();
+
+    void UpdateLayer(size_t index,
+                     ILayerRenderer* renderer,
+                     const OrthancStone::CoordinateSystem3D& plane);
+
+    void InvalidateAllLayers();
+
+    void InvalidateLayer(size_t layer);
+    
+  public:
+    virtual ~SliceViewerWidget();
+
+    size_t AddLayer(IVolumeSlicer* layer);  // Takes ownership
+
+    void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership
+
+    void RemoveLayer(size_t layerIndex);
+
+    size_t GetLayerCount() const
+    {
+      return layers_.size();
+    }
+
+    const RenderStyle& GetLayerStyle(size_t layer) const;
+
+    void SetLayerStyle(size_t layer,
+                       const RenderStyle& style);
+
+    void SetSlice(const OrthancStone::CoordinateSystem3D& plane);
+
+    const OrthancStone::CoordinateSystem3D& GetSlice() const
+    {
+      return plane_;
+    }
+
+    virtual bool HasAnimation() const
+    {
+      return true;
+    }
+
+    virtual void DoAnimation();
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/TestCairoWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,126 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "TestCairoWidget.h"
+
+#include <stdio.h>
+
+
+namespace Deprecated
+{
+  namespace Samples
+  {
+    void TestCairoWidget::DoAnimation() 
+    {
+      value_ -= 0.01f;
+      if (value_ < 0)
+      {
+        value_ = 1;
+      }
+
+      NotifyContentChanged();
+    }
+
+
+    bool TestCairoWidget::RenderCairo(OrthancStone::CairoContext& context)
+    {
+      cairo_t* cr = context.GetObject();
+
+      cairo_set_source_rgb (cr, .3, 0, 0);
+      cairo_paint(cr);
+
+      cairo_set_source_rgb(cr, 0, 1, 0);
+      cairo_rectangle(cr, width_ / 4, height_ / 4, width_ / 2, height_ / 2);
+      cairo_set_line_width(cr, 1.0);
+      cairo_fill(cr);
+
+      cairo_set_source_rgb(cr, 0, 1, value_);
+      cairo_rectangle(cr, width_ / 2 - 50, height_ / 2 - 50, 100, 100);
+      cairo_fill(cr);
+
+      return true;
+    }
+
+
+    void TestCairoWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context,
+                                               int x,
+                                               int y)
+    {
+      cairo_t* cr = context.GetObject();
+
+      cairo_set_source_rgb (cr, 1, 0, 0);
+      cairo_rectangle(cr, x - 5, y - 5, 10, 10);
+      cairo_set_line_width(cr, 1.0);
+      cairo_stroke(cr);
+
+      char buf[64];
+      sprintf(buf, "(%d,%d)", x, y);
+      UpdateStatusBar(buf);
+    }
+
+
+    TestCairoWidget::TestCairoWidget(const std::string& name, bool animate) :
+      CairoWidget(name),
+      width_(0),
+      height_(0),
+      value_(1),
+      animate_(animate)
+    {
+    }
+
+
+    void TestCairoWidget::SetSize(unsigned int width, 
+                                  unsigned int height)
+    {
+      CairoWidget::SetSize(width, height);
+      width_ = width;
+      height_ = height;
+    }
+ 
+
+    IMouseTracker* TestCairoWidget::CreateMouseTracker(OrthancStone::MouseButton button,
+                                                       int x,
+                                                       int y,
+                                                       OrthancStone::KeyboardModifiers modifiers,
+                                                       const std::vector<Touch>& touches)
+    {
+      UpdateStatusBar("Click");
+      return NULL;
+    }
+
+
+    void TestCairoWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
+                                     int x,
+                                     int y,
+                                     OrthancStone::KeyboardModifiers modifiers) 
+    {
+      UpdateStatusBar(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
+    }
+
+    
+    void TestCairoWidget::KeyPressed(OrthancStone::KeyboardKeys key,
+                                     char keyChar,
+                                     OrthancStone::KeyboardModifiers modifiers)
+    {
+      UpdateStatusBar("Key pressed: \"" + std::string(1, keyChar) + "\"");
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/TestCairoWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,79 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "CairoWidget.h"
+
+namespace Deprecated
+{
+  namespace Samples
+  {
+    class TestCairoWidget : public CairoWidget
+    {
+    private:
+      unsigned int  width_;
+      unsigned int  height_;
+      float         value_;
+      bool          animate_;
+
+    protected:
+      virtual bool RenderCairo(OrthancStone::CairoContext& context);
+
+      virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
+                                        int x,
+                                        int y);
+
+    public:
+      TestCairoWidget(const std::string& name, bool animate);
+
+      virtual void SetSize(unsigned int width, 
+                           unsigned int height);
+ 
+      virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
+                                                int x,
+                                                int y,
+                                                OrthancStone::KeyboardModifiers modifiers,
+                                                const std::vector<Touch>& touches);
+
+      virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                              int x,
+                              int y,
+                              OrthancStone::KeyboardModifiers modifiers);
+    
+      virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                              char keyChar,
+                              OrthancStone::KeyboardModifiers modifiers);
+
+      virtual bool HasAnimation() const
+      {
+        return animate_;
+      }
+      
+      virtual void DoAnimation();
+
+      virtual bool HasRenderMouseOver()
+      {
+        return true;
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/TestWorldSceneWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,149 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "TestWorldSceneWidget.h"
+
+#include <Core/OrthancException.h>
+
+#include <math.h>
+#include <stdio.h>
+
+namespace Deprecated
+{
+  namespace Samples
+  {
+    class TestWorldSceneWidget::Interactor : public IWorldSceneInteractor
+    {
+    public:
+      virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                          const ViewportGeometry& view,
+                                                          OrthancStone::MouseButton button,
+                                                          OrthancStone::KeyboardModifiers modifiers,
+                                                          int viewportX,
+                                                          int viewportY,
+                                                          double x,
+                                                          double y,
+                                                          IStatusBar* statusBar,
+                                                          const std::vector<Touch>& touches)
+      {
+        if (statusBar)
+        {
+          char buf[64];
+          sprintf(buf, "X = %0.2f, Y = %0.2f", x, y);
+          statusBar->SetMessage(buf);
+        }
+
+        return NULL;
+      }
+
+      virtual void MouseOver(OrthancStone::CairoContext& context,
+                             WorldSceneWidget& widget,
+                             const ViewportGeometry& view,
+                             double x,
+                             double y,
+                             IStatusBar* statusBar)
+      {
+        double S = 0.5;
+
+        if (fabs(x) <= S &&
+            fabs(y) <= S)
+        {
+          cairo_t* cr = context.GetObject();
+          cairo_set_source_rgb(cr, 1, 0, 0);
+          cairo_rectangle(cr, -S, -S , 2.0 * S, 2.0 * S);
+          cairo_set_line_width(cr, 1.0 / view.GetZoom());
+          cairo_stroke(cr);
+        }
+      }
+
+      virtual void MouseWheel(WorldSceneWidget& widget,
+                              OrthancStone::MouseWheelDirection direction,
+                              OrthancStone::KeyboardModifiers modifiers,
+                              IStatusBar* statusBar)
+      {
+        if (statusBar)
+        {
+          statusBar->SetMessage(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
+        }
+      }
+
+      virtual void KeyPressed(WorldSceneWidget& widget,
+                              OrthancStone::KeyboardKeys key,
+                              char keyChar,
+                              OrthancStone::KeyboardModifiers modifiers,
+                              IStatusBar* statusBar)
+      {
+        if (statusBar)
+        {
+          statusBar->SetMessage("Key pressed: \"" + std::string(1, keyChar) + "\"");
+        }
+      }
+    };
+
+
+    bool TestWorldSceneWidget::RenderScene(OrthancStone::CairoContext& context,
+                                           const ViewportGeometry& view)
+    {
+      cairo_t* cr = context.GetObject();
+
+      // Clear background
+      cairo_set_source_rgb(cr, 0, 0, 0);
+      cairo_paint(cr);
+
+      float color = static_cast<float>(count_ % 16) / 15.0f;
+      cairo_set_source_rgb(cr, 0, 1.0f - color, color);
+      cairo_rectangle(cr, -10, -.5, 20, 1);
+      cairo_fill(cr);
+
+      return true;
+    }
+
+
+    TestWorldSceneWidget::TestWorldSceneWidget(const std::string& name, bool animate) :
+      WorldSceneWidget(name),
+      interactor_(new Interactor),
+      animate_(animate),
+      count_(0)
+    {
+      SetInteractor(*interactor_);
+    }
+
+
+    OrthancStone::Extent2D TestWorldSceneWidget::GetSceneExtent()
+    {
+      return OrthancStone::Extent2D(-10, -.5, 10, .5);
+    }
+
+
+    void TestWorldSceneWidget::DoAnimation()
+    {
+      if (animate_)
+      {
+        count_++;
+        NotifyContentChanged();
+      }
+      else
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/TestWorldSceneWidget.h	Tue May 21 14:27:35 2019 +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-2019 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 "WorldSceneWidget.h"
+
+#include <memory>
+
+namespace Deprecated
+{
+  namespace Samples
+  {
+    class TestWorldSceneWidget : public WorldSceneWidget
+    {
+    private:
+      class Interactor;
+
+      std::auto_ptr<Interactor>   interactor_;
+      bool                        animate_;
+      unsigned int                count_;
+
+    protected:
+      virtual bool RenderScene(OrthancStone::CairoContext& context,
+                               const ViewportGeometry& view);
+
+    public:
+      TestWorldSceneWidget(const std::string& name, bool animate);
+
+      virtual OrthancStone::Extent2D GetSceneExtent();
+
+      virtual bool HasAnimation() const
+      {
+        return animate_;
+      }
+
+      virtual void DoAnimation();
+
+      virtual bool HasRenderMouseOver()
+      {
+        return true;
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/WidgetBase.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,166 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WidgetBase.h"
+
+#include <Core/OrthancException.h>
+#include <Core/Images/ImageProcessing.h>
+#include <Core/Logging.h>
+
+namespace Deprecated
+{
+  void WidgetBase::NotifyContentChanged()
+  {
+    if (parent_ != NULL)
+    {
+      parent_->NotifyContentChanged();
+    }
+
+    if (viewport_ != NULL)
+    {
+      viewport_->NotifyBackgroundChanged();
+    }
+  }
+
+
+  void WidgetBase::SetParent(IWidget& parent)
+  {
+    if (parent_ != NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      parent_ = &parent;
+    }
+  }    
+
+  
+  void WidgetBase::ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const 
+  {
+    // Clear the background using Orthanc
+
+    if (backgroundCleared_)
+    {
+      Orthanc::ImageProcessing::Set(target, 
+                                    backgroundColor_[0],
+                                    backgroundColor_[1],
+                                    backgroundColor_[2],
+                                    255 /* alpha */);
+    }
+  }
+
+
+  void WidgetBase::ClearBackgroundCairo(OrthancStone::CairoContext& context) const
+  {
+    // Clear the background using Cairo
+
+    if (IsBackgroundCleared())
+    {
+      uint8_t red, green, blue;
+      GetBackgroundColor(red, green, blue);
+
+      context.SetSourceColor(red, green, blue);
+      cairo_paint(context.GetObject());
+    }
+  }
+
+
+  void WidgetBase::ClearBackgroundCairo(Orthanc::ImageAccessor& target) const
+  {
+    OrthancStone::CairoSurface surface(target, false /* no alpha */);
+    OrthancStone::CairoContext context(surface);
+    ClearBackgroundCairo(context);
+  }
+
+
+  void WidgetBase::UpdateStatusBar(const std::string& message)
+  {
+    if (statusBar_ != NULL)
+    {
+      statusBar_->SetMessage(message);
+    }
+  }
+
+
+  WidgetBase::WidgetBase(const std::string& name) :
+    parent_(NULL),
+    viewport_(NULL),
+    statusBar_(NULL),
+    backgroundCleared_(false),
+    transmitMouseOver_(false),
+    name_(name)
+  {
+    backgroundColor_[0] = 0;
+    backgroundColor_[1] = 0;
+    backgroundColor_[2] = 0;
+  }
+
+
+  void WidgetBase::SetViewport(WidgetViewport& viewport)
+  {
+    if (viewport_ != NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      viewport_ = &viewport;
+    }
+  }
+
+  
+  void WidgetBase::SetBackgroundColor(uint8_t red,
+                                      uint8_t green,
+                                      uint8_t blue)
+  {
+    backgroundColor_[0] = red;
+    backgroundColor_[1] = green;
+    backgroundColor_[2] = blue;
+  }
+
+  void WidgetBase::GetBackgroundColor(uint8_t& red,
+                                      uint8_t& green,
+                                      uint8_t& blue) const
+  {
+    red = backgroundColor_[0];
+    green = backgroundColor_[1];
+    blue = backgroundColor_[2];
+  }
+
+
+  bool WidgetBase::Render(Orthanc::ImageAccessor& surface)
+  {
+#if 0
+    ClearBackgroundOrthanc(surface);
+#else
+    ClearBackgroundCairo(surface);  // Faster than Orthanc
+#endif
+
+    return true;
+  }
+
+  
+  void WidgetBase::DoAnimation()
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/WidgetBase.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,117 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "IWidget.h"
+
+#include "../../Viewport/CairoContext.h"
+#include "../Viewport/WidgetViewport.h"
+
+namespace Deprecated
+{
+  class WidgetBase : public IWidget
+  {
+  private:
+    IWidget*         parent_;
+    WidgetViewport*  viewport_;
+    IStatusBar*      statusBar_;
+    bool             backgroundCleared_;
+    uint8_t          backgroundColor_[3];
+    bool             transmitMouseOver_;
+    std::string      name_;
+
+  protected:
+    void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const;
+
+    void ClearBackgroundCairo(OrthancStone::CairoContext& context) const;
+
+    void ClearBackgroundCairo(Orthanc::ImageAccessor& target) const;
+
+    void UpdateStatusBar(const std::string& message);
+
+    IStatusBar* GetStatusBar() const
+    {
+      return statusBar_;
+    }
+
+  public:
+    WidgetBase(const std::string& name);
+
+    virtual void FitContent()
+    {
+    }
+  
+    virtual void SetParent(IWidget& parent);
+    
+    virtual void SetViewport(WidgetViewport& viewport);
+
+    void SetBackgroundCleared(bool clear)
+    {
+      backgroundCleared_ = clear;
+    }
+
+    bool IsBackgroundCleared() const
+    {
+      return backgroundCleared_;
+    }
+
+    void SetTransmitMouseOver(bool transmit)
+    {
+      transmitMouseOver_ = transmit;
+    }
+
+    void SetBackgroundColor(uint8_t red,
+                            uint8_t green,
+                            uint8_t blue);
+
+    void GetBackgroundColor(uint8_t& red,
+                            uint8_t& green,
+                            uint8_t& blue) const;
+
+    virtual void SetStatusBar(IStatusBar& statusBar)
+    {
+      statusBar_ = &statusBar;
+    }
+
+    virtual bool Render(Orthanc::ImageAccessor& surface);
+
+    virtual bool HasAnimation() const
+    {
+      return false;
+    }
+
+    virtual void DoAnimation();
+
+    virtual bool HasRenderMouseOver()
+    {
+      return transmitMouseOver_;
+    }
+
+    virtual void NotifyContentChanged();
+
+    const std::string& GetName() const
+    {
+      return name_;
+    }
+
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/WorldSceneWidget.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,231 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
+
+#include "PanMouseTracker.h"
+#include "ZoomMouseTracker.h"
+#include "PanZoomMouseTracker.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+#include <math.h>
+#include <memory>
+#include <cassert>
+
+namespace Deprecated
+{
+  // this is an adapter between a IWorldSceneMouseTracker
+  // that is tracking a mouse in scene coordinates/mm and
+  // an IMouseTracker that is tracking a mouse
+  // in screen coordinates/pixels.
+  class WorldSceneWidget::SceneMouseTracker : public IMouseTracker
+  {
+  private:
+    ViewportGeometry                        view_;
+    std::auto_ptr<IWorldSceneMouseTracker>  tracker_;
+
+  public:
+    SceneMouseTracker(const ViewportGeometry& view,
+                      IWorldSceneMouseTracker* tracker) :
+      view_(view),
+      tracker_(tracker)
+    {
+      if (tracker == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+    }
+
+    virtual void Render(Orthanc::ImageAccessor& target)
+    {
+      if (tracker_->HasRender())
+      {
+        OrthancStone::CairoSurface surface(target, false /* no alpha */);
+        OrthancStone::CairoContext context(surface);
+        view_.ApplyTransform(context);
+        tracker_->Render(context, view_.GetZoom());
+      }
+    }
+
+    virtual void MouseUp()
+    {
+      tracker_->MouseUp();
+    }
+
+    virtual void MouseMove(int x,
+                           int y,
+                           const std::vector<Touch>& displayTouches)
+    {
+      double sceneX, sceneY;
+      view_.MapPixelCenterToScene(sceneX, sceneY, x, y);
+
+      std::vector<Touch> sceneTouches;
+      for (size_t t = 0; t < displayTouches.size(); t++)
+      {
+        double sx, sy;
+        
+        view_.MapPixelCenterToScene(
+          sx, sy, (int)displayTouches[t].x, (int)displayTouches[t].y);
+        
+        sceneTouches.push_back(
+          Touch(static_cast<float>(sx), static_cast<float>(sy)));
+      }
+      tracker_->MouseMove(x, y, sceneX, sceneY, displayTouches, sceneTouches);
+    }
+  };
+
+
+  bool WorldSceneWidget::RenderCairo(OrthancStone::CairoContext& context)
+  {
+    view_.ApplyTransform(context);
+    return RenderScene(context, view_);
+  }
+
+
+  void WorldSceneWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context,
+                                              int x,
+                                              int y)
+  {
+    ViewportGeometry view = GetView();
+    view.ApplyTransform(context);
+
+    double sceneX, sceneY;
+    view.MapPixelCenterToScene(sceneX, sceneY, x, y);
+
+    if (interactor_)
+    {
+      interactor_->MouseOver(context, *this, view, sceneX, sceneY, GetStatusBar());
+    }
+  }
+
+
+  void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view)
+  {
+    view.SetSceneExtent(GetSceneExtent());
+  }
+
+
+  void WorldSceneWidget::SetSize(unsigned int width,
+                                 unsigned int height)
+  {
+    CairoWidget::SetSize(width, height);
+    view_.SetDisplaySize(width, height);
+  }
+
+
+  void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor)
+  {
+    interactor_ = &interactor;
+  }
+
+
+  void WorldSceneWidget::FitContent()
+  {
+    SetSceneExtent(view_);
+    view_.FitContent();
+
+    NotifyContentChanged();
+  }
+
+
+  void WorldSceneWidget::SetView(const ViewportGeometry& view)
+  {
+    view_ = view;
+
+    NotifyContentChanged();
+  }
+
+
+  IMouseTracker* WorldSceneWidget::CreateMouseTracker(OrthancStone::MouseButton button,
+                                                      int x,
+                                                      int y,
+                                                      OrthancStone::KeyboardModifiers modifiers,
+                                                      const std::vector<Touch>& touches)
+  {
+    double sceneX, sceneY;
+    view_.MapPixelCenterToScene(sceneX, sceneY, x, y);
+
+    // asks the Widget Interactor to provide a mouse tracker
+    std::auto_ptr<IWorldSceneMouseTracker> tracker;
+
+    if (interactor_)
+    {
+      tracker.reset(interactor_->CreateMouseTracker(*this, view_, button, modifiers, x, y, sceneX, sceneY, GetStatusBar(), touches));
+    }
+    
+    if (tracker.get() != NULL)
+    {
+      return new SceneMouseTracker(view_, tracker.release());
+    }
+    else if (hasDefaultMouseEvents_)
+    {
+      printf("has default mouse events\n");
+      if (touches.size() == 2)
+      {
+        printf("2 touches !\n");
+        return new SceneMouseTracker(view_, new PanZoomMouseTracker(*this, touches));
+      }
+      else
+      {
+        switch (button)
+        {
+          case OrthancStone::MouseButton_Middle:
+            return new SceneMouseTracker(view_, new PanMouseTracker(*this, x, y));
+
+          case OrthancStone::MouseButton_Right:
+            return new SceneMouseTracker(view_, new ZoomMouseTracker(*this, x, y));
+
+          default:
+            return NULL;
+        }
+      }
+    }
+    else
+    {
+      return NULL;
+    }
+  }
+
+
+  void WorldSceneWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
+                                    int x,
+                                    int y,
+                                    OrthancStone::KeyboardModifiers modifiers)
+  {
+    if (interactor_)
+    {
+      interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar());
+    }
+  }
+
+
+  void WorldSceneWidget::KeyPressed(OrthancStone::KeyboardKeys key,
+                                    char keyChar,
+                                    OrthancStone::KeyboardModifiers modifiers)
+  {
+    if (interactor_)
+    {
+      interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/WorldSceneWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,103 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "CairoWidget.h"
+#include "IWorldSceneInteractor.h"
+
+#include "../Toolbox/ViewportGeometry.h"
+
+namespace Deprecated
+{
+  class WorldSceneWidget : public CairoWidget
+  {
+  private:
+    class SceneMouseTracker;
+
+    ViewportGeometry       view_;
+    IWorldSceneInteractor* interactor_;
+    bool                   hasDefaultMouseEvents_;
+
+  protected:
+    virtual OrthancStone::Extent2D GetSceneExtent() = 0;
+
+    virtual bool RenderScene(OrthancStone::CairoContext& context,
+                             const ViewportGeometry& view) = 0;
+
+    // From CairoWidget
+    virtual bool RenderCairo(OrthancStone::CairoContext& context);
+
+    // From CairoWidget
+    virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
+                                      int x,
+                                      int y);
+
+    void SetSceneExtent(ViewportGeometry& geometry);
+
+  public:
+    WorldSceneWidget(const std::string& name) :
+      CairoWidget(name),
+      interactor_(NULL),
+      hasDefaultMouseEvents_(true)
+    {
+    }
+
+    void SetDefaultMouseEvents(bool value)
+    {
+      hasDefaultMouseEvents_ = value;
+    }
+
+    bool HasDefaultMouseEvents() const
+    {
+      return hasDefaultMouseEvents_;
+    }
+
+    void SetInteractor(IWorldSceneInteractor& interactor);
+
+    void SetView(const ViewportGeometry& view);
+
+    const ViewportGeometry& GetView() const
+    {
+      return view_;
+    }
+
+    virtual void SetSize(unsigned int width,
+                         unsigned int height);
+
+    virtual void FitContent();
+
+    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
+                                              int x,
+                                              int y,
+                                              OrthancStone::KeyboardModifiers modifiers,
+                                              const std::vector<Touch>& touches);
+
+    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
+                            int x,
+                            int y,
+                            OrthancStone::KeyboardModifiers modifiers);
+
+    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/ZoomMouseTracker.cpp	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,110 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "ZoomMouseTracker.h"
+
+#include <Core/Logging.h>
+#include <Core/OrthancException.h>
+
+namespace Deprecated
+{
+  ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that,
+                                     int x,
+                                     int y) :
+    that_(that),
+    originalZoom_(that.GetView().GetZoom()),
+    downX_(x),
+    downY_(y)
+  {
+    that.GetView().MapPixelCenterToScene(centerX_, centerY_, x, y);
+
+    unsigned int height = that.GetView().GetDisplayHeight();
+      
+    if (height <= 3)
+    {
+      idle_ = true;
+      LOG(WARNING) << "image is too small to zoom (current height = " << height << ")";
+    }
+    else
+    {
+      idle_ = false;
+      normalization_ = 1.0 / static_cast<double>(height - 1);
+    }
+  }
+    
+
+  void ZoomMouseTracker::Render(OrthancStone::CairoContext& context,
+                                double zoom)
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+  }
+
+
+  void ZoomMouseTracker::MouseMove(int displayX,
+                                   int displayY,
+                                   double x,
+                                   double y,
+                                   const std::vector<Touch>& displayTouches,
+                                   const std::vector<Touch>& sceneTouches)
+  {
+    static const double MIN_ZOOM = -4;
+    static const double MAX_ZOOM = 4;
+
+      
+    if (!idle_)
+    {
+      double dy = static_cast<double>(displayY - downY_) * normalization_;  // In the range [-1,1]
+      double z;
+
+      // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
+      if (dy < -1.0)
+      {
+        z = MIN_ZOOM;
+      }
+      else if (dy > 1.0)
+      {
+        z = MAX_ZOOM;
+      }
+      else
+      {
+        z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0;
+      }
+
+      z = pow(2.0, z);
+
+      ViewportGeometry view = that_.GetView();
+        
+      view.SetZoom(z * originalZoom_);
+        
+      // Correct the pan so that the original click point is kept at
+      // the same location on the display
+      double panX, panY;
+      view.GetPan(panX, panY);
+
+      int tx, ty;
+      view.MapSceneToDisplay(tx, ty, centerX_, centerY_);
+      view.SetPan(panX + static_cast<double>(downX_ - tx),
+                  panY + static_cast<double>(downY_ - ty));
+        
+      that_.SetView(view);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/Widgets/ZoomMouseTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,64 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
+
+namespace Deprecated
+{
+  class ZoomMouseTracker : public IWorldSceneMouseTracker
+  {
+  private:
+    WorldSceneWidget&  that_;
+    double             originalZoom_;
+    int                downX_;
+    int                downY_;
+    double             centerX_;
+    double             centerY_;
+    bool               idle_;
+    double             normalization_;
+    
+  public:
+    ZoomMouseTracker(WorldSceneWidget& that,
+                     int x,
+                     int y);
+    
+    virtual bool HasRender() const
+    {
+      return false;
+    }
+
+    virtual void MouseUp()
+    {
+    }
+
+    virtual void Render(OrthancStone::CairoContext& context,
+                        double zoom);
+
+    virtual void MouseMove(int displayX,
+                           int displayY,
+                           double x,
+                           double y,
+                           const std::vector<Touch>& displayTouches,
+                           const std::vector<Touch>& sceneTouches);
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Deprecated/dev.h	Tue May 21 14:27:35 2019 +0200
@@ -0,0 +1,958 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "Layers/FrameRenderer.h"
+#include "Layers/LineLayerRenderer.h"
+#include "Layers/SliceOutlineRenderer.h"
+#include "Toolbox/DownloadStack.h"
+#include "Toolbox/GeometryToolbox.h"
+#include "Toolbox/OrthancSlicesLoader.h"
+#include "Volumes/ImageBuffer3D.h"
+#include "Volumes/ISlicedVolume.h"
+#include "Widgets/SliceViewerWidget.h"
+
+#include <Core/Logging.h>
+#include <Core/Images/ImageProcessing.h>
+#include <Core/OrthancException.h>
+
+#include <boost/math/special_functions/round.hpp>
+
+
+namespace Deprecated
+{
+  // TODO: Handle errors while loading
+  class OrthancVolumeImage :
+    public ISlicedVolume,
+    public OrthancStone::IObserver
+  {
+  private:
+    OrthancSlicesLoader           loader_;
+    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
+    std::auto_ptr<DownloadStack>  downloadStack_;
+    bool                          computeRange_;
+    size_t                        pendingSlices_;
+
+    void ScheduleSliceDownload()
+    {
+      assert(downloadStack_.get() != NULL);
+
+      unsigned int slice;
+      if (downloadStack_->Pop(slice))
+      {
+        loader_.ScheduleLoadSliceImage(slice, OrthancStone::SliceImageQuality_Jpeg90);
+      }
+    }
+
+
+    static bool IsCompatible(const Slice& a,
+                             const Slice& b)
+    {
+      if (!OrthancStone::GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(),
+                                                     b.GetGeometry().GetNormal()))
+      {
+        LOG(ERROR) << "A slice in the volume image is not parallel to the others.";
+        return false;
+      }
+
+      if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat())
+      {
+        LOG(ERROR) << "The pixel format changes across the slices of the volume image.";
+        return false;
+      }
+
+      if (a.GetWidth() != b.GetWidth() ||
+          a.GetHeight() != b.GetHeight())
+      {
+        LOG(ERROR) << "The slices dimensions (width/height) are varying throughout the volume image";
+        return false;
+      }
+
+      if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
+          !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
+      {
+        LOG(ERROR) << "The pixel spacing of the slices change across the volume image";
+        return false;
+      }
+
+      return true;
+    }
+
+
+    static double GetDistance(const Slice& a,
+                              const Slice& b)
+    {
+      return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) -
+                  a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin()));
+    }
+
+
+    void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
+    {
+      assert(&message.GetOrigin() == &loader_);
+
+      if (loader_.GetSlicesCount() == 0)
+      {
+        LOG(ERROR) << "Empty volume image";
+        BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
+        return;
+      }
+
+      for (size_t i = 1; i < loader_.GetSlicesCount(); i++)
+      {
+        if (!IsCompatible(loader_.GetSlice(0), loader_.GetSlice(i)))
+        {
+          BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
+          return;
+        }
+      }
+
+      double spacingZ;
+
+      if (loader_.GetSlicesCount() > 1)
+      {
+        spacingZ = GetDistance(loader_.GetSlice(0), loader_.GetSlice(1));
+      }
+      else
+      {
+        // This is a volume with one single slice: Choose a dummy
+        // z-dimension for voxels
+        spacingZ = 1;
+      }
+
+      for (size_t i = 1; i < loader_.GetSlicesCount(); i++)
+      {
+        if (!OrthancStone::LinearAlgebra::IsNear(spacingZ, GetDistance(loader_.GetSlice(i - 1), loader_.GetSlice(i)),
+                                                 0.001 /* this is expressed in mm */))
+        {
+          LOG(ERROR) << "The distance between successive slices is not constant in a volume image";
+          BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
+          return;
+        }
+      }
+
+      unsigned int width = loader_.GetSlice(0).GetWidth();
+      unsigned int height = loader_.GetSlice(0).GetHeight();
+      Orthanc::PixelFormat format = loader_.GetSlice(0).GetConverter().GetExpectedPixelFormat();
+      LOG(INFO) << "Creating a volume image of size " << width << "x" << height
+                << "x" << loader_.GetSlicesCount() << " in " << Orthanc::EnumerationToString(format);
+
+      image_.reset(new OrthancStone::ImageBuffer3D(format, width, height, static_cast<unsigned int>(loader_.GetSlicesCount()), computeRange_));
+      image_->GetGeometry().SetAxialGeometry(loader_.GetSlice(0).GetGeometry());
+      image_->GetGeometry().SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(),
+                                               loader_.GetSlice(0).GetPixelSpacingY(), spacingZ);
+      image_->Clear();
+
+      downloadStack_.reset(new DownloadStack(static_cast<unsigned int>(loader_.GetSlicesCount())));
+      pendingSlices_ = loader_.GetSlicesCount();
+
+      for (unsigned int i = 0; i < 4; i++)  // Limit to 4 simultaneous downloads
+      {
+        ScheduleSliceDownload();
+      }
+
+      // TODO Check the DicomFrameConverter are constant
+
+      BroadcastMessage(ISlicedVolume::GeometryReadyMessage(*this));
+    }
+
+
+    void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
+    {
+      assert(&message.GetOrigin() == &loader_);
+
+      LOG(ERROR) << "Unable to download a volume image";
+      BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
+    }
+
+
+    void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
+    {
+      assert(&message.GetOrigin() == &loader_);
+
+      {
+        OrthancStone::ImageBuffer3D::SliceWriter writer(*image_, OrthancStone::VolumeProjection_Axial, message.GetSliceIndex());
+        Orthanc::ImageProcessing::Copy(writer.GetAccessor(), message.GetImage());
+      }
+
+      BroadcastMessage(ISlicedVolume::SliceContentChangedMessage
+                       (*this, message.GetSliceIndex(), message.GetSlice()));
+
+      if (pendingSlices_ == 1)
+      {
+        BroadcastMessage(ISlicedVolume::VolumeReadyMessage(*this));
+        pendingSlices_ = 0;
+      }
+      else if (pendingSlices_ > 1)
+      {
+        pendingSlices_ -= 1;
+      }
+
+      ScheduleSliceDownload();
+    }
+
+
+    void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
+    {
+      assert(&message.GetOrigin() == &loader_);
+
+      LOG(ERROR) << "Cannot download slice " << message.GetSliceIndex() << " in a volume image";
+      ScheduleSliceDownload();
+    }
+
+
+  public:
+    OrthancVolumeImage(OrthancStone::MessageBroker& broker,
+                       OrthancApiClient& orthanc,
+                       bool computeRange) :
+      ISlicedVolume(broker),
+      IObserver(broker),
+      loader_(broker, orthanc),
+      computeRange_(computeRange),
+      pendingSlices_(0)
+    {
+      loader_.RegisterObserverCallback(
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryReadyMessage>
+        (*this, &OrthancVolumeImage::OnSliceGeometryReady));
+
+      loader_.RegisterObserverCallback(
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryErrorMessage>
+        (*this, &OrthancVolumeImage::OnSliceGeometryError));
+
+      loader_.RegisterObserverCallback(
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageReadyMessage>
+        (*this, &OrthancVolumeImage::OnSliceImageReady));
+
+      loader_.RegisterObserverCallback(
+        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageErrorMessage>
+        (*this, &OrthancVolumeImage::OnSliceImageError));
+    }
+
+    void ScheduleLoadSeries(const std::string& seriesId)
+    {
+      loader_.ScheduleLoadSeries(seriesId);
+    }
+
+    void ScheduleLoadInstance(const std::string& instanceId)
+    {
+      loader_.ScheduleLoadInstance(instanceId);
+    }
+
+    void ScheduleLoadFrame(const std::string& instanceId,
+                           unsigned int frame)
+    {
+      loader_.ScheduleLoadFrame(instanceId, frame);
+    }
+
+    virtual size_t GetSlicesCount() const
+    {
+      return loader_.GetSlicesCount();
+    }
+
+    virtual const Slice& GetSlice(size_t index) const
+    {
+      return loader_.GetSlice(index);
+    }
+
+    OrthancStone::ImageBuffer3D& GetImage() const
+    {
+      if (image_.get() == NULL)
+      {
+        // The geometry is not ready yet
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+      else
+      {
+        return *image_;
+      }
+    }
+
+    bool FitWindowingToRange(RenderStyle& style,
+                             const DicomFrameConverter& converter) const
+    {
+      if (image_.get() == NULL)
+      {
+        return false;
+      }
+      else
+      {
+        return image_->FitWindowingToRange(style, converter);
+      }
+    }
+  };
+
+
+  class VolumeImageGeometry
+  {
+  private:
+    unsigned int         width_;
+    unsigned int         height_;
+    size_t               depth_;
+    double               pixelSpacingX_;
+    double               pixelSpacingY_;
+    double               sliceThickness_;
+    OrthancStone::CoordinateSystem3D   reference_;
+    DicomFrameConverter  converter_;
+
+    double ComputeAxialThickness(const OrthancVolumeImage& volume) const
+    {
+      double thickness;
+
+      size_t n = volume.GetSlicesCount();
+      if (n > 1)
+      {
+        const Slice& a = volume.GetSlice(0);
+        const Slice& b = volume.GetSlice(n - 1);
+        thickness = ((reference_.ProjectAlongNormal(b.GetGeometry().GetOrigin()) -
+                      reference_.ProjectAlongNormal(a.GetGeometry().GetOrigin())) /
+                     (static_cast<double>(n) - 1.0));
+      }
+      else
+      {
+        thickness = volume.GetSlice(0).GetThickness();
+      }
+
+      if (thickness <= 0)
+      {
+        // The slices should have been sorted with increasing Z
+        // (along the normal) by the OrthancSlicesLoader
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      }
+      else
+      {
+        return thickness;
+      }
+    }
+
+    void SetupAxial(const OrthancVolumeImage& volume)
+    {
+      const Slice& axial = volume.GetSlice(0);
+
+      width_ = axial.GetWidth();
+      height_ = axial.GetHeight();
+      depth_ = volume.GetSlicesCount();
+
+      pixelSpacingX_ = axial.GetPixelSpacingX();
+      pixelSpacingY_ = axial.GetPixelSpacingY();
+      sliceThickness_ = ComputeAxialThickness(volume);
+
+      reference_ = axial.GetGeometry();
+    }
+
+    void SetupCoronal(const OrthancVolumeImage& volume)
+    {
+      const Slice& axial = volume.GetSlice(0);
+      double axialThickness = ComputeAxialThickness(volume);
+
+      width_ = axial.GetWidth();
+      height_ = static_cast<unsigned int>(volume.GetSlicesCount());
+      depth_ = axial.GetHeight();
+
+      pixelSpacingX_ = axial.GetPixelSpacingX();
+      pixelSpacingY_ = axialThickness;
+      sliceThickness_ = axial.GetPixelSpacingY();
+
+      OrthancStone::Vector origin = axial.GetGeometry().GetOrigin();
+      origin += (static_cast<double>(volume.GetSlicesCount() - 1) *
+                 axialThickness * axial.GetGeometry().GetNormal());
+
+      reference_ = OrthancStone::CoordinateSystem3D(origin,
+                                                    axial.GetGeometry().GetAxisX(),
+                                                    - axial.GetGeometry().GetNormal());
+    }
+
+    void SetupSagittal(const OrthancVolumeImage& volume)
+    {
+      const Slice& axial = volume.GetSlice(0);
+      double axialThickness = ComputeAxialThickness(volume);
+
+      width_ = axial.GetHeight();
+      height_ = static_cast<unsigned int>(volume.GetSlicesCount());
+      depth_ = axial.GetWidth();
+
+      pixelSpacingX_ = axial.GetPixelSpacingY();
+      pixelSpacingY_ = axialThickness;
+      sliceThickness_ = axial.GetPixelSpacingX();
+
+      OrthancStone::Vector origin = axial.GetGeometry().GetOrigin();
+      origin += (static_cast<double>(volume.GetSlicesCount() - 1) *
+                 axialThickness * axial.GetGeometry().GetNormal());
+
+      reference_ = OrthancStone::CoordinateSystem3D(origin,
+                                                    axial.GetGeometry().GetAxisY(),
+                                                    axial.GetGeometry().GetNormal());
+    }
+
+  public:
+    VolumeImageGeometry(const OrthancVolumeImage& volume,
+                        OrthancStone::VolumeProjection projection)
+    {
+      if (volume.GetSlicesCount() == 0)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      }
+
+      converter_ = volume.GetSlice(0).GetConverter();
+
+      switch (projection)
+      {
+        case OrthancStone::VolumeProjection_Axial:
+          SetupAxial(volume);
+          break;
+
+        case OrthancStone::VolumeProjection_Coronal:
+          SetupCoronal(volume);
+          break;
+
+        case OrthancStone::VolumeProjection_Sagittal:
+          SetupSagittal(volume);
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      }
+    }
+
+    size_t GetSlicesCount() const
+    {
+      return depth_;
+    }
+
+    const OrthancStone::Vector& GetNormal() const
+    {
+      return reference_.GetNormal();
+    }
+
+    bool LookupSlice(size_t& index,
+                     const OrthancStone::CoordinateSystem3D& slice) const
+    {
+      bool opposite;
+      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite,
+                                                               reference_.GetNormal(),
+                                                               slice.GetNormal()))
+      {
+        return false;
+      }
+
+      double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) -
+                  reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_;
+
+      int s = static_cast<int>(boost::math::iround(z));
+
+      if (s < 0 ||
+          s >= static_cast<int>(depth_))
+      {
+        return false;
+      }
+      else
+      {
+        index = static_cast<size_t>(s);
+        return true;
+      }
+    }
+
+    Slice* GetSlice(size_t slice) const
+    {
+      if (slice >= depth_)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+      }
+      else
+      {
+        OrthancStone::CoordinateSystem3D origin(reference_.GetOrigin() +
+                                                static_cast<double>(slice) * sliceThickness_ * reference_.GetNormal(),
+                                                reference_.GetAxisX(),
+                                                reference_.GetAxisY());
+
+        return new Slice(origin, pixelSpacingX_, pixelSpacingY_, sliceThickness_,
+                         width_, height_, converter_);
+      }
+    }
+  };
+
+
+
+  class VolumeImageMPRSlicer :
+    public IVolumeSlicer,
+    public OrthancStone::IObserver
+  {
+  private:
+    class RendererFactory : public LayerReadyMessage::IRendererFactory
+    {
+    private:
+      const Orthanc::ImageAccessor&  frame_;
+      const Slice&                   slice_;
+      bool                           isFullQuality_;
+
+    public:
+      RendererFactory(const Orthanc::ImageAccessor& frame,
+                      const Slice& slice,
+                      bool isFullQuality) :
+        frame_(frame),
+        slice_(slice),
+        isFullQuality_(isFullQuality)
+      {
+      }
+
+      virtual ILayerRenderer* CreateRenderer() const
+      {
+        return FrameRenderer::CreateRenderer(frame_, slice_, isFullQuality_);
+      }
+    };
+
+
+    OrthancVolumeImage&                 volume_;
+    std::auto_ptr<VolumeImageGeometry>  axialGeometry_;
+    std::auto_ptr<VolumeImageGeometry>  coronalGeometry_;
+    std::auto_ptr<VolumeImageGeometry>  sagittalGeometry_;
+
+
+    bool IsGeometryReady() const
+    {
+      return axialGeometry_.get() != NULL;
+    }
+
+    void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message)
+    {
+      assert(&message.GetOrigin() == &volume_);
+
+      // These 3 values are only used to speed up the IVolumeSlicer
+      axialGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Axial));
+      coronalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Coronal));
+      sagittalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Sagittal));
+
+      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
+    }
+
+    void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message)
+    {
+      assert(&message.GetOrigin() == &volume_);
+
+      BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
+    }
+
+    void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message)
+    {
+      assert(&message.GetOrigin() == &volume_);
+
+      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
+    }
+
+    void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message)
+    {
+      assert(&message.GetOrigin() == &volume_);
+
+      //IVolumeSlicer::OnSliceContentChange(slice);
+
+      // TODO Improve this?
+      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
+    }
+
+    const VolumeImageGeometry& GetProjectionGeometry(OrthancStone::VolumeProjection projection)
+    {
+      if (!IsGeometryReady())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+      }
+
+      switch (projection)
+      {
+        case OrthancStone::VolumeProjection_Axial:
+          return *axialGeometry_;
+
+        case OrthancStone::VolumeProjection_Sagittal:
+          return *sagittalGeometry_;
+
+        case OrthancStone::VolumeProjection_Coronal:
+          return *coronalGeometry_;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+
+
+    bool DetectProjection(OrthancStone::VolumeProjection& projection,
+                          const OrthancStone::CoordinateSystem3D& viewportSlice)
+    {
+      bool isOpposite;  // Ignored
+
+      if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                              viewportSlice.GetNormal(),
+                                                              axialGeometry_->GetNormal()))
+      {
+        projection = OrthancStone::VolumeProjection_Axial;
+        return true;
+      }
+      else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                                   viewportSlice.GetNormal(),
+                                                                   sagittalGeometry_->GetNormal()))
+      {
+        projection = OrthancStone::VolumeProjection_Sagittal;
+        return true;
+      }
+      else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
+                                                                   viewportSlice.GetNormal(),
+                                                                   coronalGeometry_->GetNormal()))
+      {
+        projection = OrthancStone::VolumeProjection_Coronal;
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+  public:
+    VolumeImageMPRSlicer(OrthancStone::MessageBroker& broker,
+                         OrthancVolumeImage&  volume) :
+      IVolumeSlicer(broker),
+      IObserver(broker),
+      volume_(volume)
+    {
+      volume_.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage>
+        (*this, &VolumeImageMPRSlicer::OnGeometryReady));
+
+      volume_.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryErrorMessage>
+        (*this, &VolumeImageMPRSlicer::OnGeometryError));
+
+      volume_.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::ContentChangedMessage>
+        (*this, &VolumeImageMPRSlicer::OnContentChanged));
+
+      volume_.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::SliceContentChangedMessage>
+        (*this, &VolumeImageMPRSlicer::OnSliceContentChanged));
+    }
+
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
+    {
+      OrthancStone::VolumeProjection projection;
+
+      if (!IsGeometryReady() ||
+          !DetectProjection(projection, viewportSlice))
+      {
+        return false;
+      }
+      else
+      {
+        // As the slices of the volumic image are arranged in a box,
+        // we only consider one single reference slice (the one with index 0).
+        std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0));
+        slice->GetExtent(points);
+
+        return true;
+      }
+    }
+
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
+    {
+      OrthancStone::VolumeProjection projection;
+
+      if (IsGeometryReady() &&
+          DetectProjection(projection, viewportSlice))
+      {
+        const VolumeImageGeometry& geometry = GetProjectionGeometry(projection);
+
+        size_t closest;
+
+        if (geometry.LookupSlice(closest, viewportSlice))
+        {
+          bool isFullQuality = true;  // TODO
+
+          std::auto_ptr<Orthanc::Image> frame;
+
+          {
+            OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast<unsigned int>(closest));
+
+            // TODO Transfer ownership if non-axial, to avoid memcpy
+            frame.reset(Orthanc::Image::Clone(reader.GetAccessor()));
+          }
+
+          std::auto_ptr<Slice> slice(geometry.GetSlice(closest));
+
+          RendererFactory factory(*frame, *slice, isFullQuality);
+
+          BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice->GetGeometry()));
+          return;
+        }
+      }
+
+      // Error
+      OrthancStone::CoordinateSystem3D slice;
+      BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, slice));
+    }
+  };
+
+
+  class VolumeImageInteractor :
+    public IWorldSceneInteractor,
+    public OrthancStone::IObserver
+  {
+  private:
+    SliceViewerWidget&                  widget_;
+    OrthancStone::VolumeProjection      projection_;
+    std::auto_ptr<VolumeImageGeometry>  slices_;
+    size_t                              slice_;
+
+  protected:
+    void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message)
+    {
+      if (slices_.get() == NULL)
+      {
+        const OrthancVolumeImage& image =
+          dynamic_cast<const OrthancVolumeImage&>(message.GetOrigin());
+
+        slices_.reset(new VolumeImageGeometry(image, projection_));
+        SetSlice(slices_->GetSlicesCount() / 2);
+
+        widget_.FitContent();
+      }
+    }
+
+    virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
+                                                        const ViewportGeometry& view,
+                                                        OrthancStone::MouseButton button,
+                                                        OrthancStone::KeyboardModifiers modifiers,
+                                                        int viewportX,
+                                                        int viewportY,
+                                                        double x,
+                                                        double y,
+                                                        IStatusBar* statusBar,
+                                                        const std::vector<Touch>& touches) ORTHANC_OVERRIDE
+    {
+      return  NULL;
+    }
+
+    virtual void MouseOver(OrthancStone::CairoContext& context,
+                           WorldSceneWidget& widget,
+                           const ViewportGeometry& view,
+                           double x,
+                           double y,
+                           IStatusBar* statusBar) ORTHANC_OVERRIDE
+    {
+    }
+
+    virtual void MouseWheel(WorldSceneWidget& widget,
+                            OrthancStone::MouseWheelDirection direction,
+                            OrthancStone::KeyboardModifiers modifiers,
+                            IStatusBar* statusBar) ORTHANC_OVERRIDE
+    {
+      int scale = (modifiers & OrthancStone::KeyboardModifiers_Control ? 10 : 1);
+
+      switch (direction)
+      {
+        case OrthancStone::MouseWheelDirection_Up:
+          OffsetSlice(-scale);
+          break;
+
+        case OrthancStone::MouseWheelDirection_Down:
+          OffsetSlice(scale);
+          break;
+
+        default:
+          break;
+      }
+    }
+
+    virtual void KeyPressed(WorldSceneWidget& widget,
+                            OrthancStone::KeyboardKeys key,
+                            char keyChar,
+                            OrthancStone::KeyboardModifiers modifiers,
+                            IStatusBar* statusBar) ORTHANC_OVERRIDE
+    {
+      switch (keyChar)
+      {
+        case 's':
+          widget.FitContent();
+          break;
+
+        default:
+          break;
+      }
+    }
+
+  public:
+    VolumeImageInteractor(OrthancStone::MessageBroker& broker,
+                          OrthancVolumeImage& volume,
+                          SliceViewerWidget& widget,
+                          OrthancStone::VolumeProjection projection) :
+      IObserver(broker),
+      widget_(widget),
+      projection_(projection)
+    {
+      widget.SetInteractor(*this);
+
+      volume.RegisterObserverCallback(
+        new OrthancStone::Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage>
+        (*this, &VolumeImageInteractor::OnGeometryReady));
+    }
+
+    bool IsGeometryReady() const
+    {
+      return slices_.get() != NULL;
+    }
+
+    size_t GetSlicesCount() const
+    {
+      if (slices_.get() == NULL)
+      {
+        return 0;
+      }
+      else
+      {
+        return slices_->GetSlicesCount();
+      }
+    }
+
+    void OffsetSlice(int offset)
+    {
+      if (slices_.get() != NULL)
+      {
+        int slice = static_cast<int>(slice_) + offset;
+
+        if (slice < 0)
+        {
+          slice = 0;
+        }
+
+        if (slice >= static_cast<int>(slices_->GetSlicesCount()))
+        {
+          slice = static_cast<unsigned int>(slices_->GetSlicesCount()) - 1;
+        }
+
+        if (slice != static_cast<int>(slice_))
+        {
+          SetSlice(slice);
+        }
+      }
+    }
+
+    void SetSlice(size_t slice)
+    {
+      if (slices_.get() != NULL)
+      {
+        slice_ = slice;
+
+        std::auto_ptr<Slice> tmp(slices_->GetSlice(slice_));
+        widget_.SetSlice(tmp->GetGeometry());
+      }
+    }
+  };
+
+
+
+  class ReferenceLineSource : public IVolumeSlicer
+  {
+  private:
+    class RendererFactory : public LayerReadyMessage::IRendererFactory
+    {
+    private:
+      double                     x1_;
+      double                     y1_;
+      double                     x2_;
+      double                     y2_;
+      const OrthancStone::CoordinateSystem3D&  slice_;
+
+    public:
+      RendererFactory(double x1,
+                      double y1,
+                      double x2,
+                      double y2,
+                      const OrthancStone::CoordinateSystem3D& slice) :
+        x1_(x1),
+        y1_(y1),
+        x2_(x2),
+        y2_(y2),
+        slice_(slice)
+      {
+      }
+
+      virtual ILayerRenderer* CreateRenderer() const
+      {
+        return new LineLayerRenderer(x1_, y1_, x2_, y2_, slice_);
+      }
+    };
+
+    SliceViewerWidget&  otherPlane_;
+
+  public:
+    ReferenceLineSource(OrthancStone::MessageBroker& broker,
+                        SliceViewerWidget&  otherPlane) :
+      IVolumeSlicer(broker),
+      otherPlane_(otherPlane)
+    {
+      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
+    }
+
+    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
+                           const OrthancStone::CoordinateSystem3D& viewportSlice)
+    {
+      return false;
+    }
+
+    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
+    {
+      Slice reference(viewportSlice, 0.001);
+
+      OrthancStone::Vector p, d;
+
+      const OrthancStone::CoordinateSystem3D& slice = otherPlane_.GetSlice();
+
+      // Compute the line of intersection between the two slices
+      if (!OrthancStone::GeometryToolbox::IntersectTwoPlanes(p, d,
+                                                             slice.GetOrigin(), slice.GetNormal(),
+                                                             viewportSlice.GetOrigin(), viewportSlice.GetNormal()))
+      {
+        // The two slice are parallel, don't try and display the intersection
+        BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry()));
+      }
+      else
+      {
+        double x1, y1, x2, y2;
+        viewportSlice.ProjectPoint(x1, y1, p);
+        viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d);
+
+        const OrthancStone::Extent2D extent = otherPlane_.GetSceneExtent();
+
+        if (OrthancStone::GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2,
+                                                               x1, y1, x2, y2,
+                                                               extent.GetX1(), extent.GetY1(),
+                                                               extent.GetX2(), extent.GetY2()))
+        {
+          RendererFactory factory(x1, y1, x2, y2, slice);
+          BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, reference.GetGeometry()));
+        }
+        else
+        {
+          // Error: Parallel slices
+          BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry()));
+        }
+      }
+    }
+  };
+}
--- a/Framework/Layers/CircleMeasureTracker.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CircleMeasureTracker.h"
-
-#include <stdio.h>
-#include <boost/math/constants/constants.hpp>
-
-namespace Deprecated
-{
-  CircleMeasureTracker::CircleMeasureTracker(IStatusBar* statusBar,
-                                             const OrthancStone::CoordinateSystem3D& slice,
-                                             double x, 
-                                             double y,
-                                             uint8_t red,
-                                             uint8_t green,
-                                             uint8_t blue,
-                                             const Orthanc::Font& font) :
-    statusBar_(statusBar),
-    slice_(slice),
-    x1_(x),
-    y1_(y),
-    x2_(x),
-    y2_(y),
-    font_(font)
-  {
-    color_[0] = red;
-    color_[1] = green;
-    color_[2] = blue;
-  }
-    
-
-  void CircleMeasureTracker::Render(OrthancStone::CairoContext& context,
-                                    double zoom)
-  {
-    double x = (x1_ + x2_) / 2.0;
-    double y = (y1_ + y2_) / 2.0;
-
-    OrthancStone::Vector tmp;
-    OrthancStone::LinearAlgebra::AssignVector(tmp, x2_ - x1_, y2_ - y1_);
-    double r = boost::numeric::ublas::norm_2(tmp) / 2.0;
-
-    context.SetSourceColor(color_[0], color_[1], color_[2]);
-
-    cairo_t* cr = context.GetObject();
-    cairo_save(cr);
-    cairo_set_line_width(cr, 2.0 / zoom);
-    cairo_translate(cr, x, y);
-    cairo_arc(cr, 0, 0, r, 0, 2.0 * boost::math::constants::pi<double>());
-    cairo_stroke_preserve(cr);
-    cairo_stroke(cr);
-    cairo_restore(cr);
-
-    context.DrawText(font_, FormatRadius(), x, y, OrthancStone::BitmapAnchor_Center);
-  }
-    
-
-  double CircleMeasureTracker::GetRadius() const  // In millimeters
-  {
-    OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
-    OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
-    return boost::numeric::ublas::norm_2(b - a) / 2.0;
-  }
-
-
-  std::string CircleMeasureTracker::FormatRadius() const
-  {
-    char buf[64];
-    sprintf(buf, "%0.01f cm", GetRadius() / 10.0);
-    return buf;
-  }
-
-  void CircleMeasureTracker::MouseMove(int displayX,
-                                       int displayY,
-                                       double x,
-                                       double y,
-                                       const std::vector<Touch>& displayTouches,
-                                       const std::vector<Touch>& sceneTouches)
-  {
-    x2_ = x;
-    y2_ = y;
-
-    if (statusBar_ != NULL)
-    {
-      statusBar_->SetMessage("Circle radius: " + FormatRadius());
-    }
-  }
-}
--- a/Framework/Layers/CircleMeasureTracker.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "../Widgets/IWorldSceneMouseTracker.h"
-
-#include "../Viewport/IStatusBar.h"
-#include "../Toolbox/CoordinateSystem3D.h"
-
-#include <Core/Images/Font.h>
-
-namespace Deprecated
-{
-  class CircleMeasureTracker : public IWorldSceneMouseTracker
-  {
-  private:
-    IStatusBar*           statusBar_;
-    OrthancStone::CoordinateSystem3D    slice_;
-    double                x1_;
-    double                y1_;
-    double                x2_;
-    double                y2_;
-    uint8_t               color_[3];
-    const Orthanc::Font&  font_;
-
-  public:
-    CircleMeasureTracker(IStatusBar* statusBar,
-                         const OrthancStone::CoordinateSystem3D& slice,
-                         double x, 
-                         double y,
-                         uint8_t red,
-                         uint8_t green,
-                         uint8_t blue,
-                         const Orthanc::Font& font);
-    
-    virtual bool HasRender() const
-    {
-      return true;
-    }
-
-    virtual void Render(OrthancStone::CairoContext& context,
-                        double zoom);
-    
-    double GetRadius() const;  // In millimeters
-
-    std::string FormatRadius() const;
-
-    virtual void MouseUp()
-    {
-      // Possibly create a new landmark "volume" with the circle in subclasses
-    }
-
-    virtual void MouseMove(int displayX,
-                           int displayY,
-                           double x,
-                           double y,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
-  };
-}
--- a/Framework/Layers/ColorFrameRenderer.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ColorFrameRenderer.h"
-
-#include <Core/OrthancException.h>
-#include <Core/Images/Image.h>
-#include <Core/Images/ImageProcessing.h>
-
-namespace Deprecated
-{
-  OrthancStone::CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style)
-  {
-    std::auto_ptr<OrthancStone::CairoSurface> display
-      (new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
-
-    Orthanc::ImageAccessor target;
-    display->GetWriteableAccessor(target);
-    
-    Orthanc::ImageProcessing::Convert(target, *frame_);
-
-    return display.release();
-  }
-
-
-  ColorFrameRenderer::ColorFrameRenderer(const Orthanc::ImageAccessor& frame,
-                                         const OrthancStone::CoordinateSystem3D& framePlane,
-                                         double pixelSpacingX,
-                                         double pixelSpacingY,
-                                         bool isFullQuality) :
-    FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality),
-    frame_(Orthanc::Image::Clone(frame))
-  {
-    if (frame_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    if (frame_->GetFormat() != Orthanc::PixelFormat_RGB24)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-    }
-  }
-}
--- a/Framework/Layers/ColorFrameRenderer.h	Tue May 21 13:27:54 2019 +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-2019 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 "FrameRenderer.h"
-
-namespace Deprecated
-{
-  class ColorFrameRenderer : public FrameRenderer
-  {
-  private:
-    std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In RGB24
-
-  protected:
-    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
-
-  public:
-    ColorFrameRenderer(const Orthanc::ImageAccessor& frame,
-                       const OrthancStone::CoordinateSystem3D& framePlane,
-                       double pixelSpacingX,
-                       double pixelSpacingY,
-                       bool isFullQuality);
-  };
-}
--- a/Framework/Layers/DicomSeriesVolumeSlicer.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "DicomSeriesVolumeSlicer.h"
-
-#include "FrameRenderer.h"
-#include "../Toolbox/DicomFrameConverter.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/lexical_cast.hpp>
-
-namespace Deprecated
-{
-
-  void DicomSeriesVolumeSlicer::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
-  {
-    if (message.GetOrigin().GetSlicesCount() > 0)
-    {
-      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
-    }
-    else
-    {
-      BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
-    }
-  }
-
-  void DicomSeriesVolumeSlicer::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
-  {
-    BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
-  }
-
-
-  class DicomSeriesVolumeSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory
-  {
-  private:
-    const OrthancSlicesLoader::SliceImageReadyMessage&  message_;
-
-  public:
-    RendererFactory(const OrthancSlicesLoader::SliceImageReadyMessage& message) :
-      message_(message)
-    {
-    }
-
-    virtual ILayerRenderer* CreateRenderer() const
-    {
-      bool isFull = (message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPng ||
-                     message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPam);
-
-      return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull);
-    }
-  };
-
-  void DicomSeriesVolumeSlicer::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
-  {
-    // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache)
-    BroadcastMessage(FrameReadyMessage(*this, message.GetImage(), 
-                                  message.GetEffectiveQuality(), message.GetSlice()));
-
-    // then notify that the layer is ready for rendering
-    RendererFactory factory(message);
-    BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, message.GetSlice().GetGeometry()));
-  }
-
-  void DicomSeriesVolumeSlicer::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
-  {
-    BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, message.GetSlice().GetGeometry()));
-  }
-
-
-  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
-                                                   OrthancApiClient& orthanc) :
-    IVolumeSlicer(broker),
-    IObserver(broker),
-    loader_(broker, orthanc),
-    quality_(OrthancStone::SliceImageQuality_FullPng)
-  {
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage>
-        (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady));
-
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage>
-      (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError));
-
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage>
-        (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady));
-
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage>
-      (*this, &DicomSeriesVolumeSlicer::OnSliceImageError));
-  }
-
-  
-  void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId)
-  {
-    loader_.ScheduleLoadSeries(seriesId);
-  }
-
-
-  void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId)
-  {
-    loader_.ScheduleLoadInstance(instanceId);
-  }
-
-
-  void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId,
-                                          unsigned int frame)
-  {
-    loader_.ScheduleLoadFrame(instanceId, frame);
-  }
-
-
-  bool DicomSeriesVolumeSlicer::GetExtent(std::vector<OrthancStone::Vector>& points,
-                                          const OrthancStone::CoordinateSystem3D& viewportSlice)
-  {
-    size_t index;
-
-    if (loader_.IsGeometryReady() &&
-        loader_.LookupSlice(index, viewportSlice))
-    {
-      loader_.GetSlice(index).GetExtent(points);
-      return true;
-    }
-    else
-    {
-      return false;
-    }
-  }
-
-  
-  void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
-  {
-    size_t index;
-
-    if (loader_.IsGeometryReady() &&
-        loader_.LookupSlice(index, viewportSlice))
-    {
-      loader_.ScheduleLoadSliceImage(index, quality_);
-    }
-  }
-}
--- a/Framework/Layers/DicomSeriesVolumeSlicer.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IVolumeSlicer.h"
-#include "../Toolbox/IWebService.h"
-#include "../Toolbox/OrthancSlicesLoader.h"
-#include "../Toolbox/OrthancApiClient.h"
-
-namespace Deprecated
-{  
-  // this class is in charge of loading a Frame.
-  // once it's been loaded (first the geometry and then the image),
-  // messages are sent to observers so they can use it
-  class DicomSeriesVolumeSlicer :
-    public IVolumeSlicer,
-    public OrthancStone::IObserver
-    //private OrthancSlicesLoader::ISliceLoaderObserver
-  {
-  public:
-    // TODO: Add "frame" and "instanceId"
-    class FrameReadyMessage : public OrthancStone::OriginMessage<DicomSeriesVolumeSlicer>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      const Orthanc::ImageAccessor&  frame_;
-      OrthancStone::SliceImageQuality              imageQuality_;
-      const Slice&                   slice_;
-
-    public:
-      FrameReadyMessage(DicomSeriesVolumeSlicer& origin,
-                        const Orthanc::ImageAccessor& frame,
-                        OrthancStone::SliceImageQuality imageQuality,
-                        const Slice& slice) :
-        OriginMessage(origin),
-        frame_(frame),
-        imageQuality_(imageQuality),
-        slice_(slice)
-      {
-      }
-
-      const Orthanc::ImageAccessor& GetFrame() const
-      {
-        return frame_;
-      }
-
-      OrthancStone::SliceImageQuality GetImageQuality() const
-      {
-        return imageQuality_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-    
-  private:
-    class RendererFactory;
-    
-    OrthancSlicesLoader  loader_;
-    OrthancStone::SliceImageQuality    quality_;
-
-  public:
-    DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
-                            OrthancApiClient& orthanc);
-
-    void LoadSeries(const std::string& seriesId);
-
-    void LoadInstance(const std::string& instanceId);
-
-    void LoadFrame(const std::string& instanceId,
-                   unsigned int frame);
-
-    void SetImageQuality(OrthancStone::SliceImageQuality quality)
-    {
-      quality_ = quality;
-    }
-
-    OrthancStone::SliceImageQuality GetImageQuality() const
-    {
-      return quality_;
-    }
-
-    size_t GetSlicesCount() const
-    {
-      return loader_.GetSlicesCount();
-    }
-
-    const Slice& GetSlice(size_t slice) const 
-    {
-      return loader_.GetSlice(slice);
-    }
-
-    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
-                           const OrthancStone::CoordinateSystem3D& viewportSlice);
-
-    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice);
-
-protected:
-    void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message);
-    void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message);
-    void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message);
-    void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message);
-  };
-}
--- a/Framework/Layers/DicomStructureSetSlicer.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "DicomStructureSetSlicer.h"
-
-namespace Deprecated
-{
-  class DicomStructureSetSlicer::Renderer : public ILayerRenderer
-  {
-  private:
-    class Structure
-    {
-    private:
-      bool                                                         visible_;
-      uint8_t                                                      red_;
-      uint8_t                                                      green_;
-      uint8_t                                                      blue_;
-      std::string                                                  name_;
-      std::vector< std::vector<OrthancStone::DicomStructureSet::PolygonPoint> >  polygons_;
-
-    public:
-      Structure(OrthancStone::DicomStructureSet& structureSet,
-                const OrthancStone::CoordinateSystem3D& plane,
-                size_t index) :
-        name_(structureSet.GetStructureName(index))
-      {
-        structureSet.GetStructureColor(red_, green_, blue_, index);
-        visible_ = structureSet.ProjectStructure(polygons_, index, plane);
-      }
-
-      void Render(OrthancStone::CairoContext& context)
-      {
-        if (visible_)
-        {
-          cairo_t* cr = context.GetObject();
-        
-          context.SetSourceColor(red_, green_, blue_);
-
-          for (size_t i = 0; i < polygons_.size(); i++)
-          {
-            cairo_move_to(cr, polygons_[i][0].first, polygons_[i][0].second);
-
-            for (size_t j = 1; j < polygons_[i].size(); j++)
-            {
-              cairo_line_to(cr, polygons_[i][j].first, polygons_[i][j].second);
-            }
-
-            cairo_line_to(cr, polygons_[i][0].first, polygons_[i][0].second);
-            cairo_stroke(cr);
-          }
-        }
-      }
-    };
-
-    typedef std::list<Structure*>  Structures;
-    
-    OrthancStone::CoordinateSystem3D  plane_;
-    Structures          structures_;
-    
-  public:
-    Renderer(OrthancStone::DicomStructureSet& structureSet,
-             const OrthancStone::CoordinateSystem3D& plane) :
-      plane_(plane)
-    {
-      for (size_t k = 0; k < structureSet.GetStructureCount(); k++)
-      {
-        structures_.push_back(new Structure(structureSet, plane, k));
-      }
-    }
-
-    virtual ~Renderer()
-    {
-      for (Structures::iterator it = structures_.begin();
-           it != structures_.end(); ++it)
-      {
-        delete *it;
-      }
-    }
-
-    virtual bool RenderLayer(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view)
-    {
-      cairo_set_line_width(context.GetObject(), 2.0f / view.GetZoom());
-
-      for (Structures::const_iterator it = structures_.begin();
-           it != structures_.end(); ++it)
-      {
-        assert(*it != NULL);
-        (*it)->Render(context);
-      }
-
-      return true;
-    }
-
-    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
-    {
-      return plane_;
-    }
-
-    virtual void SetLayerStyle(const RenderStyle& style)
-    {
-    }
-    
-    virtual bool IsFullQuality()
-    {
-      return true;
-    }
-  };
-
-
-  class DicomStructureSetSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory
-  {
-  private:
-    OrthancStone::DicomStructureSet&         structureSet_;
-    const OrthancStone::CoordinateSystem3D&  plane_;
-
-  public:
-    RendererFactory(OrthancStone::DicomStructureSet& structureSet,
-                    const OrthancStone::CoordinateSystem3D&  plane) :
-      structureSet_(structureSet),
-      plane_(plane)
-    {
-    }
-
-    virtual ILayerRenderer* CreateRenderer() const
-    {
-      return new Renderer(structureSet_, plane_);
-    }
-  };
-  
-
-  DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
-                                                   StructureSetLoader& loader) :
-    IVolumeSlicer(broker),
-    IObserver(broker),
-    loader_(loader)
-  {
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomStructureSetSlicer, StructureSetLoader::ContentChangedMessage>
-      (*this, &DicomStructureSetSlicer::OnStructureSetLoaded));
-  }
-
-
-  void DicomStructureSetSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane)
-  {
-    if (loader_.HasStructureSet())
-    {
-      RendererFactory factory(loader_.GetStructureSet(), viewportPlane);
-      BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, viewportPlane));
-    }
-  }
-}
--- a/Framework/Layers/DicomStructureSetSlicer.h	Tue May 21 13:27:54 2019 +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-2019 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 "IVolumeSlicer.h"
-#include "../Volumes/StructureSetLoader.h"
-
-namespace Deprecated
-{
-  class DicomStructureSetSlicer :
-    public IVolumeSlicer,
-    public OrthancStone::IObserver
-  {
-  private:
-    class Renderer;
-    class RendererFactory;
-
-    StructureSetLoader& loader_;
-
-    void OnStructureSetLoaded(const IVolumeLoader::ContentChangedMessage& message)
-    {
-      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
-    }
-
-  public:
-    DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
-                            StructureSetLoader& loader);
-
-    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
-                           const OrthancStone::CoordinateSystem3D& viewportPlane)
-    {
-      return false;
-    }
-
-    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane);
-  };
-}
--- a/Framework/Layers/FrameRenderer.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "FrameRenderer.h"
-
-#include "GrayscaleFrameRenderer.h"
-#include "ColorFrameRenderer.h"
-
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  FrameRenderer::FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane,
-                               double pixelSpacingX,
-                               double pixelSpacingY,
-                               bool isFullQuality) :
-    framePlane_(framePlane),
-    pixelSpacingX_(pixelSpacingX),
-    pixelSpacingY_(pixelSpacingY),
-    isFullQuality_(isFullQuality)
-  {
-  }
-
-
-  bool FrameRenderer::RenderLayer(OrthancStone::CairoContext& context,
-                                  const ViewportGeometry& view)
-  {    
-    if (!style_.visible_)
-    {
-      return true;
-    }
-
-    if (display_.get() == NULL)
-    {
-      display_.reset(GenerateDisplay(style_));
-    }
-
-    assert(display_.get() != NULL);
-
-    cairo_t *cr = context.GetObject();
-
-    cairo_save(cr);
-
-    cairo_matrix_t transform;
-    cairo_matrix_init_identity(&transform);
-    cairo_matrix_scale(&transform, pixelSpacingX_, pixelSpacingY_);
-    cairo_matrix_translate(&transform, -0.5, -0.5);
-    cairo_transform(cr, &transform);
-
-    //cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-    cairo_set_source_surface(cr, display_->GetObject(), 0, 0);
-
-    switch (style_.interpolation_)
-    {
-      case OrthancStone::ImageInterpolation_Nearest:
-        cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
-        break;
-
-      case OrthancStone::ImageInterpolation_Bilinear:
-        cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR);
-        break;
-
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    cairo_paint_with_alpha(cr, style_.alpha_);
-
-    if (style_.drawGrid_)
-    {
-      context.SetSourceColor(style_.drawColor_);
-      cairo_set_line_width(cr, 0.5 / view.GetZoom());
-
-      for (unsigned int x = 0; x <= display_->GetWidth(); x++)
-      {
-        cairo_move_to(cr, x, 0);
-        cairo_line_to(cr, x, display_->GetHeight());
-      }
-
-      for (unsigned int y = 0; y <= display_->GetHeight(); y++)
-      {
-        cairo_move_to(cr, 0, y);
-        cairo_line_to(cr, display_->GetWidth(), y);
-      }
-
-      cairo_stroke(cr);
-    }
-
-    cairo_restore(cr);
-
-    return true;
-  }
-
-
-  void FrameRenderer::SetLayerStyle(const RenderStyle& style)
-  {
-    style_ = style;
-    display_.reset(NULL);
-  }
-
-
-  ILayerRenderer* FrameRenderer::CreateRenderer(const Orthanc::ImageAccessor& frame,
-                                                const Deprecated::Slice& framePlane,
-                                                bool isFullQuality)
-  {
-    if (frame.GetFormat() == Orthanc::PixelFormat_RGB24)
-    {
-      return new ColorFrameRenderer(frame,
-                                    framePlane.GetGeometry(), 
-                                    framePlane.GetPixelSpacingX(),
-                                    framePlane.GetPixelSpacingY(), isFullQuality);
-    }
-    else
-    {
-      return new GrayscaleFrameRenderer(frame,
-                                        framePlane.GetConverter(),
-                                        framePlane.GetGeometry(), 
-                                        framePlane.GetPixelSpacingX(),
-                                        framePlane.GetPixelSpacingY(), isFullQuality);
-    }
-  }
-}
--- a/Framework/Layers/FrameRenderer.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ILayerRenderer.h"
-
-#include "../Toolbox/Slice.h"
-
-namespace Deprecated
-{
-  class FrameRenderer : public ILayerRenderer
-  {
-  private:
-    OrthancStone::CoordinateSystem3D            framePlane_;
-    double                        pixelSpacingX_;
-    double                        pixelSpacingY_;
-    RenderStyle                   style_;
-    bool                          isFullQuality_;
-    std::auto_ptr<OrthancStone::CairoSurface>   display_;
-
-  protected:
-    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style) = 0;
-
-  public:
-    FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane,
-                  double pixelSpacingX,
-                  double pixelSpacingY,
-                  bool isFullQuality);
-
-    virtual bool RenderLayer(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view);
-
-    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
-    {
-      return framePlane_;
-    }
-
-    virtual void SetLayerStyle(const RenderStyle& style);
-
-    virtual bool IsFullQuality() 
-    {
-      return isFullQuality_;
-    }
-
-    // TODO: Avoid cloning the "frame"
-    static ILayerRenderer* CreateRenderer(const Orthanc::ImageAccessor& frame,
-                                          const Deprecated::Slice& framePlane,
-                                          bool isFullQuality);
-  };
-}
--- a/Framework/Layers/GrayscaleFrameRenderer.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "GrayscaleFrameRenderer.h"
-
-#include <Core/Images/Image.h>
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  OrthancStone::CairoSurface* GrayscaleFrameRenderer::GenerateDisplay(const RenderStyle& style)
-  {
-    assert(frame_->GetFormat() == Orthanc::PixelFormat_Float32);
-
-    std::auto_ptr<OrthancStone::CairoSurface> result;
-
-    float windowCenter, windowWidth;
-    style.ComputeWindowing(windowCenter, windowWidth,
-                           defaultWindowCenter_, defaultWindowWidth_);
-
-    float x0 = windowCenter - windowWidth / 2.0f;
-    float x1 = windowCenter + windowWidth / 2.0f;
-
-    //LOG(INFO) << "Window: " << x0 << " => " << x1;
-
-    result.reset(new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */));
-
-    const uint8_t* lut = NULL;
-    if (style.applyLut_)
-    {
-      if (Orthanc::EmbeddedResources::GetFileResourceSize(style.lut_) != 3 * 256)
-      {
-        // Invalid colormap
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-
-      lut = reinterpret_cast<const uint8_t*>(Orthanc::EmbeddedResources::GetFileResourceBuffer(style.lut_));
-    }
-
-    Orthanc::ImageAccessor target;
-    result->GetWriteableAccessor(target);
-    
-    const unsigned int width = target.GetWidth();
-    const unsigned int height = target.GetHeight();
-    
-    for (unsigned int y = 0; y < height; y++)
-    {
-      const float* p = reinterpret_cast<const float*>(frame_->GetConstRow(y));
-      uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
-
-      for (unsigned int x = 0; x < width; x++, p++, q += 4)
-      {
-        uint8_t v = 0;
-        if (windowWidth >= 0.001f)  // Avoid division by zero
-        {
-          if (*p >= x1)
-          {
-            v = 255;
-          }
-          else if (*p <= x0)
-          {
-            v = 0;
-          }
-          else
-          {
-            // https://en.wikipedia.org/wiki/Linear_interpolation
-            v = static_cast<uint8_t>(255.0f * (*p - x0) / (x1 - x0));
-          }
-
-          if (style.reverse_ ^ (photometric_ == Orthanc::PhotometricInterpretation_Monochrome1))
-          {
-            v = 255 - v;
-          }
-        }
-
-        if (style.applyLut_)
-        {
-          assert(lut != NULL);
-          q[3] = 255;
-          q[2] = lut[3 * v];
-          q[1] = lut[3 * v + 1];
-          q[0] = lut[3 * v + 2];
-        }
-        else
-        {
-          q[3] = 255;
-          q[2] = v;
-          q[1] = v;
-          q[0] = v;
-        }
-      }
-    }
-
-    return result.release();
-  }
-
-
-  GrayscaleFrameRenderer::GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame,
-                                                 const Deprecated::DicomFrameConverter& converter,
-                                                 const OrthancStone::CoordinateSystem3D& framePlane,
-                                                 double pixelSpacingX,
-                                                 double pixelSpacingY,
-                                                 bool isFullQuality) :
-    FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality),
-    frame_(Orthanc::Image::Clone(frame)),
-    defaultWindowCenter_(static_cast<float>(converter.GetDefaultWindowCenter())),
-    defaultWindowWidth_(static_cast<float>(converter.GetDefaultWindowWidth())),
-    photometric_(converter.GetPhotometricInterpretation())
-  {
-    if (frame_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    converter.ConvertFrameInplace(frame_);
-    assert(frame_.get() != NULL);
-
-    if (frame_->GetFormat() != Orthanc::PixelFormat_Float32)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-    }
-  }
-}
--- a/Framework/Layers/GrayscaleFrameRenderer.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "FrameRenderer.h"
-#include "../Toolbox/DicomFrameConverter.h"
-
-namespace Deprecated
-{
-  class GrayscaleFrameRenderer : public FrameRenderer
-  {
-  private:
-    std::auto_ptr<Orthanc::ImageAccessor>   frame_;  // In Float32
-    float                                   defaultWindowCenter_;
-    float                                   defaultWindowWidth_;
-    Orthanc::PhotometricInterpretation      photometric_;
-
-  protected:
-    virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style);
-
-  public:
-    GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame,
-                           const Deprecated::DicomFrameConverter& converter,
-                           const OrthancStone::CoordinateSystem3D& framePlane,
-                           double pixelSpacingX,
-                           double pixelSpacingY,
-                           bool isFullQuality);
-  };
-}
--- a/Framework/Layers/ILayerRenderer.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "../Viewport/CairoContext.h"
-#include "../Toolbox/CoordinateSystem3D.h"
-#include "../Toolbox/ViewportGeometry.h"
-#include "RenderStyle.h"
-
-namespace Deprecated
-{
-  class ILayerRenderer : public boost::noncopyable
-  {
-  public:
-    virtual ~ILayerRenderer()
-    {
-    }
-    
-    virtual bool RenderLayer(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view) = 0;
-
-    virtual void SetLayerStyle(const RenderStyle& style) = 0;
-
-    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() = 0;
-    
-    virtual bool IsFullQuality() = 0;
-  };
-}
--- a/Framework/Layers/IVolumeSlicer.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ILayerRenderer.h"
-#include "../Toolbox/Slice.h"
-#include "../../Framework/Messages/IObservable.h"
-#include "../../Framework/Messages/IMessage.h"
-#include "Core/Images/Image.h"
-#include <boost/shared_ptr.hpp>
-
-namespace Deprecated
-{
-  class IVolumeSlicer : public OrthancStone::IObservable
-  {
-  public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeSlicer);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeSlicer);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeSlicer);
-
-    class SliceContentChangedMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      const Deprecated::Slice& slice_;
-
-    public:
-      SliceContentChangedMessage(IVolumeSlicer& origin,
-                                 const Deprecated::Slice& slice) :
-        OriginMessage(origin),
-        slice_(slice)
-      {
-      }
-
-      const Deprecated::Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-    
-
-    class LayerReadyMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    public:
-      class IRendererFactory : public boost::noncopyable
-      {
-      public:
-        virtual ~IRendererFactory()
-        {
-        }
-
-        virtual ILayerRenderer* CreateRenderer() const = 0;
-      };
-    
-    private:
-      const IRendererFactory&    factory_;
-      const OrthancStone::CoordinateSystem3D&  slice_;
-
-    public:
-      LayerReadyMessage(IVolumeSlicer& origin,
-                        const IRendererFactory& rendererFactory,
-                        const OrthancStone::CoordinateSystem3D& slice) :
-        OriginMessage(origin),
-        factory_(rendererFactory),
-        slice_(slice)
-      {
-      }
-
-      ILayerRenderer* CreateRenderer() const
-      {
-        return factory_.CreateRenderer();
-      }
-
-      const OrthancStone::CoordinateSystem3D& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-
-    class LayerErrorMessage : public OrthancStone::OriginMessage<IVolumeSlicer>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      const OrthancStone::CoordinateSystem3D&  slice_;
-
-    public:
-      LayerErrorMessage(IVolumeSlicer& origin,
-                        const OrthancStone::CoordinateSystem3D& slice) :
-        OriginMessage(origin),
-        slice_(slice)
-      {
-      }
-
-      const OrthancStone::CoordinateSystem3D& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-
-    IVolumeSlicer(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
-    virtual ~IVolumeSlicer()
-    {
-    }
-
-    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
-                           const OrthancStone::CoordinateSystem3D& viewportSlice) = 0;
-
-    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) = 0;
-  };
-}
--- a/Framework/Layers/LineLayerRenderer.cpp	Tue May 21 13:27:54 2019 +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-2019 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 "LineLayerRenderer.h"
-
-namespace Deprecated
-{
-  LineLayerRenderer::LineLayerRenderer(double x1,
-                                       double y1,
-                                       double x2,
-                                       double y2,
-                                       const OrthancStone::CoordinateSystem3D& plane) : 
-    x1_(x1),
-    y1_(y1),
-    x2_(x2),
-    y2_(y2),
-    plane_(plane)
-  {
-    RenderStyle style;
-    SetLayerStyle(style);
-  }
-
-
-  bool LineLayerRenderer::RenderLayer(OrthancStone::CairoContext& context,
-                                      const ViewportGeometry& view)
-  {
-    if (visible_)
-    {
-      context.SetSourceColor(color_);
-
-      cairo_t *cr = context.GetObject();
-      cairo_set_line_width(cr, 1.0 / view.GetZoom());
-      cairo_move_to(cr, x1_, y1_);
-      cairo_line_to(cr, x2_, y2_);
-      cairo_stroke(cr);
-    }
-
-    return true;
-  }
-
-
-  void LineLayerRenderer::SetLayerStyle(const RenderStyle& style)
-  {
-    visible_ = style.visible_;
-    color_[0] = style.drawColor_[0];
-    color_[1] = style.drawColor_[1];
-    color_[2] = style.drawColor_[2];
-  }
-}
--- a/Framework/Layers/LineLayerRenderer.h	Tue May 21 13:27:54 2019 +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-2019 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 "ILayerRenderer.h"
-
-namespace Deprecated
-{
-  class LineLayerRenderer : public ILayerRenderer
-  {
-  private:
-    double              x1_;
-    double              y1_;
-    double              x2_;
-    double              y2_;
-    OrthancStone::CoordinateSystem3D  plane_;
-    bool                visible_;
-    uint8_t             color_[3];
-
-  public:
-    LineLayerRenderer(double x1,
-                      double y1,
-                      double x2,
-                      double y2,
-                      const OrthancStone::CoordinateSystem3D& plane);
-
-    virtual bool RenderLayer(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view);
-
-    virtual void SetLayerStyle(const RenderStyle& style);
-
-    virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane()
-    {
-      return plane_;
-    }
-    
-    virtual bool IsFullQuality()
-    {
-      return true;
-    }
-  };
-}
--- a/Framework/Layers/LineMeasureTracker.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "LineMeasureTracker.h"
-
-#include <stdio.h>
-
-namespace Deprecated
-{
-  LineMeasureTracker::LineMeasureTracker(IStatusBar* statusBar,
-                                         const OrthancStone::CoordinateSystem3D& slice,
-                                         double x, 
-                                         double y,
-                                         uint8_t red,
-                                         uint8_t green,
-                                         uint8_t blue,
-                                         const Orthanc::Font& font) :
-    statusBar_(statusBar),
-    slice_(slice),
-    x1_(x),
-    y1_(y),
-    x2_(x),
-    y2_(y),
-    font_(font)
-  {
-    color_[0] = red;
-    color_[1] = green;
-    color_[2] = blue;
-  }
-    
-
-  void LineMeasureTracker::Render(OrthancStone::CairoContext& context,
-                                  double zoom)
-  {
-    context.SetSourceColor(color_[0], color_[1], color_[2]);
-
-    cairo_t* cr = context.GetObject();
-    cairo_set_line_width(cr, 2.0 / zoom);
-    cairo_move_to(cr, x1_, y1_);
-    cairo_line_to(cr, x2_, y2_);
-    cairo_stroke(cr);
-
-    if (y2_ - y1_ < 0)
-    {
-      context.DrawText(font_, FormatLength(), x2_, y2_ - 5, OrthancStone::BitmapAnchor_BottomCenter);
-    }
-    else
-    {
-      context.DrawText(font_, FormatLength(), x2_, y2_ + 5, OrthancStone::BitmapAnchor_TopCenter);
-    }
-  }
-    
-
-  double LineMeasureTracker::GetLength() const  // In millimeters
-  {
-    OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_);
-    OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_);
-    return boost::numeric::ublas::norm_2(b - a);
-  }
-
-
-  std::string LineMeasureTracker::FormatLength() const
-  {
-    char buf[64];
-    sprintf(buf, "%0.01f cm", GetLength() / 10.0);
-    return buf;
-  }
-
-  void LineMeasureTracker::MouseMove(int displayX,
-                                     int displayY,
-                                     double x,
-                                     double y,
-                                     const std::vector<Touch>& displayTouches,
-                                     const std::vector<Touch>& sceneTouches)
-  {
-    x2_ = x;
-    y2_ = y;
-
-    if (statusBar_ != NULL)
-    {
-      statusBar_->SetMessage("Line length: " + FormatLength());
-    }
-  }
-}
--- a/Framework/Layers/LineMeasureTracker.h	Tue May 21 13:27:54 2019 +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-2019 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 "../Widgets/IWorldSceneMouseTracker.h"
-
-#include "../Viewport/IStatusBar.h"
-#include "../Toolbox/CoordinateSystem3D.h"
-
-namespace Deprecated
-{
-  class LineMeasureTracker : public IWorldSceneMouseTracker
-  {
-  private:
-    IStatusBar*           statusBar_;
-    OrthancStone::CoordinateSystem3D    slice_;
-    double                x1_;
-    double                y1_;
-    double                x2_;
-    double                y2_;
-    uint8_t               color_[3];
-    unsigned int          fontSize_;
-    const Orthanc::Font&  font_;
-
-  public:
-    LineMeasureTracker(IStatusBar* statusBar,
-                       const OrthancStone::CoordinateSystem3D& slice,
-                       double x, 
-                       double y,
-                       uint8_t red,
-                       uint8_t green,
-                       uint8_t blue,
-                       const Orthanc::Font& font);
-
-    virtual bool HasRender() const
-    {
-      return true;
-    }
-
-    virtual void Render(OrthancStone::CairoContext& context,
-                        double zoom);
-    
-    double GetLength() const;  // In millimeters
-
-    std::string FormatLength() const;
-
-    virtual void MouseUp()
-    {
-      // Possibly create a new landmark "volume" with the line in subclasses
-    }
-
-    virtual void MouseMove(int displayX,
-                           int displayY,
-                           double x,
-                           double y,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
-  };
-}
--- a/Framework/Layers/RenderStyle.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "RenderStyle.h"
-
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  RenderStyle::RenderStyle()
-  {
-    visible_ = true;
-    reverse_ = false;
-    windowing_ = OrthancStone::ImageWindowing_Custom;
-    alpha_ = 1;
-    applyLut_ = false;
-    lut_ = Orthanc::EmbeddedResources::COLORMAP_HOT;
-    drawGrid_ = false;
-    drawColor_[0] = 255;
-    drawColor_[1] = 255;
-    drawColor_[2] = 255;
-    customWindowCenter_ = 128;
-    customWindowWidth_ = 256;
-    interpolation_ = OrthancStone::ImageInterpolation_Nearest;
-    fontSize_ = 14;
-  }
-
-
-  void RenderStyle::ComputeWindowing(float& targetCenter,
-                                     float& targetWidth,
-                                     float defaultCenter,
-                                     float defaultWidth) const
-  {
-    if (windowing_ == OrthancStone::ImageWindowing_Custom)
-    {
-      targetCenter = customWindowCenter_;
-      targetWidth = customWindowWidth_;
-    }
-    else
-    {
-      return ::OrthancStone::ComputeWindowing
-        (targetCenter, targetWidth, windowing_, defaultCenter, defaultWidth);
-    }
-  }
-
-  
-  void RenderStyle::SetColor(uint8_t red,
-                             uint8_t green,
-                             uint8_t blue)
-  {
-    drawColor_[0] = red;
-    drawColor_[1] = green;
-    drawColor_[2] = blue;
-  }
-}
--- a/Framework/Layers/RenderStyle.h	Tue May 21 13:27:54 2019 +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-2019 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 "../StoneEnumerations.h"
-
-#include <EmbeddedResources.h>
-
-#include <stdint.h>
-
-namespace Deprecated
-{
-  struct RenderStyle
-  {
-    bool visible_;
-    bool reverse_;
-    OrthancStone::ImageWindowing windowing_;
-    float alpha_;   // In [0,1]
-    bool applyLut_;
-    Orthanc::EmbeddedResources::FileResourceId  lut_;
-    bool drawGrid_;
-    uint8_t drawColor_[3];
-    float customWindowCenter_;
-    float customWindowWidth_;
-    OrthancStone::ImageInterpolation interpolation_;
-    unsigned int fontSize_;
-    
-    RenderStyle();
-
-    void ComputeWindowing(float& targetCenter,
-                          float& targetWidth,
-                          float defaultCenter,
-                          float defaultWidth) const;
-
-    void SetColor(uint8_t red,
-                  uint8_t green,
-                  uint8_t blue);
-  };
-}
--- a/Framework/Layers/SeriesFrameRendererFactory.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "SeriesFrameRendererFactory.h"
-
-#include "FrameRenderer.h"
-
-#include <OrthancException.h>
-#include <Logging.h>
-#include <Toolbox.h>
-#include <Plugins/Samples/Common/OrthancPluginException.h>
-#include <Plugins/Samples/Common/DicomDatasetReader.h>
-
-
-namespace Deprecated
-{
-  void SeriesFrameRendererFactory::ReadCurrentFrameDataset(size_t frame)
-  {
-    if (currentDataset_.get() != NULL &&
-        (fast_ || currentFrame_ == frame))
-    {
-      // The frame has not changed since the previous call, no need to
-      // update the DICOM dataset
-      return; 
-    }
-      
-    currentDataset_.reset(loader_->DownloadDicom(frame));
-    currentFrame_ = frame;
-
-    if (currentDataset_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-
-
-  void SeriesFrameRendererFactory::GetCurrentPixelSpacing(double& spacingX,
-                                                          double& spacingY) const
-  {
-    if (currentDataset_.get() == NULL)
-    {
-      // There was no previous call "ReadCurrentFrameDataset()"
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-    
-    GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *currentDataset_);
-  }
-
-
-  double SeriesFrameRendererFactory::GetCurrentSliceThickness() const
-  {
-    if (currentDataset_.get() == NULL)
-    {
-      // There was no previous call "ReadCurrentFrameDataset()"
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-    
-    try
-    {
-      OrthancPlugins::DicomDatasetReader reader(*currentDataset_);
-
-      double thickness;
-      if (reader.GetDoubleValue(thickness, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS))
-      {
-        return thickness;
-      }
-    }
-    catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
-    {
-    }
-
-    // Some arbitrary large slice thickness
-    return std::numeric_limits<double>::infinity();
-  }
-
-
-  SeriesFrameRendererFactory::SeriesFrameRendererFactory(ISeriesLoader* loader,   // Takes ownership
-                                                         bool fast) :
-    loader_(loader),
-    currentFrame_(0),
-    fast_(fast)
-  {
-    if (loader == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-
-
-  bool SeriesFrameRendererFactory::GetExtent(double& x1,
-                                             double& y1,
-                                             double& x2,
-                                             double& y2,
-                                             const SliceGeometry& viewportSlice)
-  {
-    if (currentDataset_.get() == NULL)
-    {
-      // There has been no previous call to
-      // "CreateLayerRenderer". Read some arbitrary DICOM frame, the
-      // one at the middle of the series.
-      unsigned int depth = loader_->GetGeometry().GetSliceCount();
-      ReadCurrentFrameDataset(depth / 2);
-    }
-
-    double spacingX, spacingY;
-    GetCurrentPixelSpacing(spacingX, spacingY);
-
-    return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2, 
-                                             viewportSlice, 
-                                             loader_->GetGeometry().GetSlice(0), 
-                                             loader_->GetWidth(), 
-                                             loader_->GetHeight(),
-                                             spacingX, spacingY);
-  }
-
-
-  ILayerRenderer* SeriesFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice)
-  {
-    size_t closest;
-    double distance;
-
-    bool isOpposite;
-    if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, loader_->GetGeometry().GetNormal(), viewportSlice.GetNormal()) ||
-        !loader_->GetGeometry().ComputeClosestSlice(closest, distance, viewportSlice.GetOrigin()))
-    {
-      // Unable to compute the slice in the series that is the
-      // closest to the slice displayed by the viewport
-      return NULL;
-    }
-
-    ReadCurrentFrameDataset(closest);
-    assert(currentDataset_.get() != NULL);
-        
-    double spacingX, spacingY;
-    GetCurrentPixelSpacing(spacingX, spacingY);
-
-    if (distance <= GetCurrentSliceThickness() / 2.0)
-    {
-      SliceGeometry frameSlice(*currentDataset_);
-      return FrameRenderer::CreateRenderer(loader_->DownloadFrame(closest), 
-                                           frameSlice,
-                                           *currentDataset_, 
-                                           spacingX, spacingY,
-                                           true);
-    }
-    else
-    {
-      // The closest slice of the series is too far away from the
-      // slice displayed by the viewport
-      return NULL;
-    }
-  }
-
-
-  ISliceableVolume& SeriesFrameRendererFactory::GetSourceVolume() const
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-  }
-}
--- a/Framework/Layers/SeriesFrameRendererFactory.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ILayerRendererFactory.h"
-
-#include "../Toolbox/ISeriesLoader.h"
-
-namespace Deprecated
-{
-  class SeriesFrameRendererFactory : public ILayerRendererFactory
-  {
-  private:
-    std::auto_ptr<ISeriesLoader>  loader_;
-    size_t                        currentFrame_;
-    bool                          fast_;
-
-    std::auto_ptr<OrthancPlugins::IDicomDataset>  currentDataset_;
-
-    void ReadCurrentFrameDataset(size_t frame);
-
-    void GetCurrentPixelSpacing(double& spacingX,
-                                double& spacingY) const;
-
-    double GetCurrentSliceThickness() const;
-
-  public:
-    SeriesFrameRendererFactory(ISeriesLoader* loader,   // Takes ownership
-                               bool fast);
-
-    virtual bool GetExtent(double& x1,
-                           double& y1,
-                           double& x2,
-                           double& y2,
-                           const SliceGeometry& viewportSlice);
-
-    virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice);
-
-    virtual bool HasSourceVolume() const
-    {
-      return false;
-    }
-
-    virtual ISliceableVolume& GetSourceVolume() const;
-  };
-}
--- a/Framework/Layers/SingleFrameRendererFactory.cpp	Tue May 21 13:27:54 2019 +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
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "SingleFrameRendererFactory.h"
-
-#include "FrameRenderer.h"
-#include "../Toolbox/MessagingToolbox.h"
-#include "../Toolbox/DicomFrameConverter.h"
-
-#include <OrthancException.h>
-#include <Plugins/Samples/Common/FullOrthancDataset.h>
-#include <Plugins/Samples/Common/DicomDatasetReader.h>
-
-namespace Deprecated
-{
-  SingleFrameRendererFactory::SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc,
-                                                         const std::string& instanceId,
-                                                         unsigned int frame) :
-    orthanc_(orthanc),
-    instance_(instanceId),
-    frame_(frame)
-  {
-    dicom_.reset(new OrthancPlugins::FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags"));
-
-    DicomFrameConverter converter;
-    converter.ReadParameters(*dicom_);
-    format_ = converter.GetExpectedPixelFormat();
-  }
-
-
-  bool SingleFrameRendererFactory::GetExtent(double& x1,
-                                             double& y1,
-                                             double& x2,
-                                             double& y2,
-                                             const SliceGeometry& viewportSlice)
-  {
-    // Assume that PixelSpacingX == PixelSpacingY == 1
-
-    OrthancPlugins::DicomDatasetReader reader(*dicom_);
-
-    unsigned int width, height;
-
-    if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) ||
-        !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    x1 = 0;
-    y1 = 0;
-    x2 = static_cast<double>(width);
-    y2 = static_cast<double>(height);
-
-    return true;
-  }
-
-
-  ILayerRenderer* SingleFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice)
-  {
-    SliceGeometry frameSlice(*dicom_);
-    return FrameRenderer::CreateRenderer(MessagingToolbox::DecodeFrame(orthanc_, instance_, frame_, format_), 
-                                         frameSlice, *dicom_, 1, 1, true);
-  }
-
-
-  ISliceableVolume& SingleFrameRendererFactory::GetSourceVolume() const
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-  }
-}
--- a/Framework/Layers/SingleFrameRendererFactory.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ILayerRendererFactory.h"
-#include <Plugins/Samples/Common/IOrthancConnection.h>
-
-namespace Deprecated
-{
-  class SingleFrameRendererFactory : public ILayerRendererFactory
-  {
-  private:
-    OrthancPlugins::IOrthancConnection&           orthanc_;
-    std::auto_ptr<OrthancPlugins::IDicomDataset>  dicom_;
-
-    std::string           instance_;
-    unsigned int          frame_;
-    Orthanc::PixelFormat  format_;
-
-  public:
-    SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc,
-                               const std::string& instanceId,
-                               unsigned int frame);
-
-    const OrthancPlugins::IDicomDataset& GetDataset() const
-    {
-      return *dicom_;
-    }
-
-    SliceGeometry GetSliceGeometry()
-    {
-      return SliceGeometry(*dicom_);
-    }
-
-    virtual bool GetExtent(double& x1,
-                           double& y1,
-                           double& x2,
-                           double& y2,
-                           const SliceGeometry& viewportSlice);
-
-    virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice);
-
-    virtual bool HasSourceVolume() const
-    {
-      return false;
-    }
-
-    virtual ISliceableVolume& GetSourceVolume() const;
-  };
-}
--- a/Framework/Layers/SliceOutlineRenderer.cpp	Tue May 21 13:27:54 2019 +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-2019 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 "SliceOutlineRenderer.h"
-
-namespace Deprecated
-{
-  bool SliceOutlineRenderer::RenderLayer(OrthancStone::CairoContext& context,
-                                         const ViewportGeometry& view)
-  {
-    if (style_.visible_)
-    {
-      cairo_t *cr = context.GetObject();
-      cairo_save(cr);
-
-      context.SetSourceColor(style_.drawColor_);
-
-      double x1 = -0.5 * pixelSpacingX_;
-      double y1 = -0.5 * pixelSpacingY_;
-        
-      cairo_set_line_width(cr, 1.0 / view.GetZoom());
-      cairo_rectangle(cr, x1, y1,
-                      static_cast<double>(width_) * pixelSpacingX_,
-                      static_cast<double>(height_) * pixelSpacingY_);
-
-      double handleSize = 10.0f / view.GetZoom();
-      cairo_move_to(cr, x1 + handleSize, y1);
-      cairo_line_to(cr, x1, y1 + handleSize);
-
-      cairo_stroke(cr);
-      cairo_restore(cr);
-    }
-
-    return true;
-  }
-}
--- a/Framework/Layers/SliceOutlineRenderer.h	Tue May 21 13:27:54 2019 +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-2019 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 "ILayerRenderer.h"
-#include "../Toolbox/Slice.h"
-
-namespace Deprecated
-{
-  class SliceOutlineRenderer : public ILayerRenderer
-  {
-  private:
-    OrthancStone::CoordinateSystem3D  geometry_;
-    double              pixelSpacingX_;
-    double              pixelSpacingY_;
-    unsigned int        width_;
-    unsigned int        height_;
-    RenderStyle         style_;
-
-  public:
-    SliceOutlineRenderer(const Slice& slice) :
-      geometry_(slice.GetGeometry()),
-      pixelSpacingX_(slice.GetPixelSpacingX()),
-      pixelSpacingY_(slice.GetPixelSpacingY()),
-      width_(slice.GetWidth()),
-      height_(slice.GetHeight())
-    {
-    }
-
-    virtual bool RenderLayer(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view);
-
-    virtual void SetLayerStyle(const RenderStyle& style)
-    {
-      style_ = style;
-    }
-
-    virtual const OrthancStone::CoordinateSystem3D& GetLayerSlice()
-    {
-      return geometry_;
-    }
-
-    virtual bool IsFullQuality()
-    {
-      return true;
-    }
-  };
-}
--- a/Framework/Radiography/RadiographyDicomLayer.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.cpp	Tue May 21 14:27:35 2019 +0200
@@ -22,7 +22,7 @@
 #include "RadiographyDicomLayer.h"
 
 #include "RadiographyScene.h"
-#include "../Toolbox/DicomFrameConverter.h"
+#include "../Deprecated/Toolbox/DicomFrameConverter.h"
 
 #include <Core/OrthancException.h>
 #include <Core/Images/Image.h>
--- a/Framework/Radiography/RadiographyDicomLayer.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.h	Tue May 21 14:27:35 2019 +0200
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "../Toolbox/DicomFrameConverter.h"
+#include "../Deprecated/Toolbox/DicomFrameConverter.h"
 #include "RadiographyLayer.h"
 
 #include <Plugins/Samples/Common/FullOrthancDataset.h>
--- a/Framework/Radiography/RadiographyLayerCropTracker.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerCropTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -22,8 +22,8 @@
 #pragma once
 
 #include "../Toolbox/UndoRedoStack.h"
-#include "../Toolbox/ViewportGeometry.h"
-#include "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Deprecated/Toolbox/ViewportGeometry.h"
+#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h"
 #include "RadiographyScene.h"
 
 namespace OrthancStone
--- a/Framework/Radiography/RadiographyLayerMaskTracker.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerMaskTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -22,8 +22,8 @@
 #pragma once
 
 #include "../Toolbox/UndoRedoStack.h"
-#include "../Toolbox/ViewportGeometry.h"
-#include "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Deprecated/Toolbox/ViewportGeometry.h"
+#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h"
 #include "RadiographyScene.h"
 
 namespace OrthancStone
--- a/Framework/Radiography/RadiographyLayerMoveTracker.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerMoveTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../Toolbox/UndoRedoStack.h"
-#include "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h"
 #include "RadiographyScene.h"
 
 namespace OrthancStone
--- a/Framework/Radiography/RadiographyLayerResizeTracker.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerResizeTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../Toolbox/UndoRedoStack.h"
-#include "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h"
 #include "RadiographyScene.h"
 
 namespace OrthancStone
--- a/Framework/Radiography/RadiographyLayerRotateTracker.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyLayerRotateTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -22,8 +22,8 @@
 #pragma once
 
 #include "../Toolbox/UndoRedoStack.h"
-#include "../Toolbox/ViewportGeometry.h"
-#include "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Deprecated/Toolbox/ViewportGeometry.h"
+#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h"
 #include "RadiographyScene.h"
 
 
--- a/Framework/Radiography/RadiographyScene.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.cpp	Tue May 21 14:27:35 2019 +0200
@@ -25,7 +25,7 @@
 #include "RadiographyDicomLayer.h"
 #include "RadiographyTextLayer.h"
 #include "RadiographyMaskLayer.h"
-#include "../Toolbox/DicomFrameConverter.h"
+#include "../Deprecated/Toolbox/DicomFrameConverter.h"
 
 #include <Core/Images/Image.h>
 #include <Core/Images/ImageProcessing.h>
--- a/Framework/Radiography/RadiographyScene.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.h	Tue May 21 14:27:35 2019 +0200
@@ -22,9 +22,9 @@
 #pragma once
 
 #include "RadiographyLayer.h"
-#include "../Toolbox/DicomFrameConverter.h"
-#include "../Toolbox/OrthancApiClient.h"
-#include "Framework/StoneEnumerations.h"
+#include "../Deprecated/Toolbox/DicomFrameConverter.h"
+#include "../Deprecated/Toolbox/OrthancApiClient.h"
+#include "../StoneEnumerations.h"
 #include "Core/Images/Image.h"
 #include "Core/Images/ImageProcessing.h"
 
--- a/Framework/Radiography/RadiographySceneReader.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographySceneReader.cpp	Tue May 21 14:27:35 2019 +0200
@@ -21,7 +21,7 @@
 
 #include "RadiographySceneReader.h"
 
-#include <Framework/Toolbox/DicomFrameConverter.h>
+#include "../Deprecated/Toolbox/DicomFrameConverter.h"
 
 #include <Core/Images/FontRegistry.h>
 #include <Core/Images/PngReader.h>
--- a/Framework/Radiography/RadiographySceneReader.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographySceneReader.h	Tue May 21 14:27:35 2019 +0200
@@ -26,7 +26,7 @@
 #include "RadiographyDicomLayer.h"
 #include "RadiographyMaskLayer.h"
 #include "RadiographyTextLayer.h"
-#include "../Toolbox/OrthancApiClient.h"
+#include "../Deprecated/Toolbox/OrthancApiClient.h"
 
 #include <json/value.h>
 #include <Core/Images/FontRegistry.h>
--- a/Framework/Radiography/RadiographyWidget.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyWidget.h	Tue May 21 14:27:35 2019 +0200
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "../Widgets/WorldSceneWidget.h"
+#include "../Deprecated/Widgets/WorldSceneWidget.h"
 #include "RadiographyScene.h"
 
 
--- a/Framework/Radiography/RadiographyWindowingTracker.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Radiography/RadiographyWindowingTracker.h	Tue May 21 14:27:35 2019 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../Toolbox/UndoRedoStack.h"
-#include "../Widgets/IWorldSceneMouseTracker.h"
+#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h"
 #include "RadiographyScene.h"
 
 namespace OrthancStone
--- a/Framework/SmartLoader.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,291 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "SmartLoader.h"
-#include "Layers/DicomSeriesVolumeSlicer.h"
-#include "Messages/MessageForwarder.h"
-#include "Core/Images/Image.h"
-#include "Framework/Widgets/SliceViewerWidget.h"
-#include "Framework/StoneException.h"
-#include "Framework/Layers/FrameRenderer.h"
-#include "Core/Logging.h"
-
-namespace Deprecated
-{
-  enum CachedSliceStatus
-  {
-    CachedSliceStatus_ScheduledToLoad,
-    CachedSliceStatus_GeometryLoaded,
-    CachedSliceStatus_ImageLoaded
-  };
-
-  class SmartLoader::CachedSlice : public IVolumeSlicer
-  {
-  public:
-    class RendererFactory : public LayerReadyMessage::IRendererFactory
-    {
-    private:
-      const CachedSlice&  that_;
-
-    public:
-      RendererFactory(const CachedSlice& that) :
-        that_(that)
-      {
-      }
-
-      virtual ILayerRenderer* CreateRenderer() const
-      {
-        bool isFull = (that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPng ||
-                       that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPam);
-
-        return FrameRenderer::CreateRenderer(*that_.image_, *that_.slice_, isFull);
-      }
-    };
-    
-    unsigned int                    sliceIndex_;
-    std::auto_ptr<Slice>            slice_;
-    boost::shared_ptr<Orthanc::ImageAccessor>   image_;
-    OrthancStone::SliceImageQuality               effectiveQuality_;
-    CachedSliceStatus               status_;
-
-  public:
-    CachedSlice(OrthancStone::MessageBroker& broker) :
-    IVolumeSlicer(broker)
-    {
-    }
-
-    virtual ~CachedSlice()
-    {
-    }
-
-    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
-                           const OrthancStone::CoordinateSystem3D& viewportSlice)
-    {
-      // TODO: viewportSlice is not used !!!!
-      slice_->GetExtent(points);
-      return true;
-    }
-
-    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
-    {
-      // TODO: viewportSlice is not used !!!!
-
-      // it has already been loaded -> trigger the "layer ready" message immediately otherwise, do nothing now.  The LayerReady will be triggered
-      // once the VolumeSlicer is ready
-      if (status_ == CachedSliceStatus_ImageLoaded)
-      {
-        LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId();
-
-        RendererFactory factory(*this);   
-        BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry()));
-      }
-      else
-      {
-        LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is not loaded yet): " << slice_->GetOrthancInstanceId();
-      }
-    }
-
-    CachedSlice* Clone() const
-    {
-      CachedSlice* output = new CachedSlice(GetBroker());
-      output->sliceIndex_ = sliceIndex_;
-      output->slice_.reset(slice_->Clone());
-      output->image_ = image_;
-      output->effectiveQuality_ = effectiveQuality_;
-      output->status_ = status_;
-
-      return output;
-    }
-
-  };
-
-
-  SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker,  
-                           OrthancApiClient& orthancApiClient) :
-    IObservable(broker),
-    IObserver(broker),
-    imageQuality_(OrthancStone::SliceImageQuality_FullPam),
-    orthancApiClient_(orthancApiClient)
-  {
-  }
-
-  void SmartLoader::SetFrameInWidget(SliceViewerWidget& sliceViewer, 
-                                     size_t layerIndex, 
-                                     const std::string& instanceId, 
-                                     unsigned int frame)
-  {
-    // TODO: check if this frame has already been loaded or is already being loaded.
-    // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately"
-    //   (it can not be immediate because Observers needs to register first and this is done after this method returns)
-    // - if currently loading, we need to return an object that will observe the existing VolumeSlicer and forward
-    //   the messages to its observables
-    // in both cases, we must be carefull about objects lifecycle !!!
-
-    std::auto_ptr<IVolumeSlicer> layerSource;
-    std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
-    SmartLoader::CachedSlice* cachedSlice = NULL;
-
-    if (cachedSlices_.find(sliceKeyId) != cachedSlices_.end()) // && cachedSlices_[sliceKeyId]->status_ == CachedSliceStatus_Loaded)
-    {
-      layerSource.reset(cachedSlices_[sliceKeyId]->Clone());
-      cachedSlice = dynamic_cast<SmartLoader::CachedSlice*>(layerSource.get());
-    }
-    else
-    {
-      layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
-      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
-      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
-      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
-      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
-      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
-    }
-
-    // make sure that the widget registers the events before we trigger them
-    if (sliceViewer.GetLayerCount() == layerIndex)
-    {
-      sliceViewer.AddLayer(layerSource.release());
-    }
-    else if (sliceViewer.GetLayerCount() > layerIndex)
-    {
-      sliceViewer.ReplaceLayer(layerIndex, layerSource.release());
-    }
-    else
-    {
-      throw OrthancStone::StoneException(OrthancStone::ErrorCode_CanOnlyAddOneLayerAtATime);
-    }
-
-    if (cachedSlice != NULL)
-    {
-      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice));
-    }
-
-  }
-
-  void SmartLoader::PreloadSlice(const std::string instanceId, 
-                                 unsigned int frame)
-  {
-    // TODO: reactivate -> need to be able to ScheduleLayerLoading in IVolumeSlicer without calling ScheduleLayerCreation
-    return;
-    // TODO: check if it is already in the cache
-
-
-
-    // create the slice in the cache with "empty" data
-    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
-    cachedSlice->slice_.reset(new Slice(instanceId, frame));
-    cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad;
-    std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
-
-    LOG(WARNING) << "Will preload: " << sliceKeyId;
-
-    cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
-
-    std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
-
-    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
-    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
-    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
-    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
-    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
-
-    // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache
-    preloadingInstances_[sliceKeyId] = boost::shared_ptr<IVolumeSlicer>(layerSource.release());
-  }
-
-
-//  void PreloadStudy(const std::string studyId)
-//  {
-//    /* TODO */
-//  }
-
-//  void PreloadSeries(const std::string seriesId)
-//  {
-//    /* TODO */
-//  }
-
-
-  void SmartLoader::OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
-  {
-    const DicomSeriesVolumeSlicer& source =
-      dynamic_cast<const DicomSeriesVolumeSlicer&>(message.GetOrigin());
-
-    // save/replace the slice in cache
-    const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount()
-    std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
-                              boost::lexical_cast<std::string>(slice.GetFrame()));
-
-    LOG(WARNING) << "Geometry ready: " << sliceKeyId;
-
-    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
-    cachedSlice->slice_.reset(slice.Clone());
-    cachedSlice->effectiveQuality_ = source.GetImageQuality();
-    cachedSlice->status_ = CachedSliceStatus_GeometryLoaded;
-
-    cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
-
-    // re-emit original Layer message to observers
-    BroadcastMessage(message);
-  }
-
-
-  void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message)
-  {
-    // save/replace the slice in cache
-    const Slice& slice = message.GetSlice();
-    std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
-                              boost::lexical_cast<std::string>(slice.GetFrame()));
-
-    LOG(WARNING) << "Image ready: " << sliceKeyId;
-
-    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
-    cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame()));
-    cachedSlice->effectiveQuality_ = message.GetImageQuality();
-    cachedSlice->slice_.reset(message.GetSlice().Clone());
-    cachedSlice->status_ = CachedSliceStatus_ImageLoaded;
-
-    cachedSlices_[sliceKeyId] = cachedSlice;
-
-    // re-emit original Layer message to observers
-    BroadcastMessage(message);
-  }
-
-
-  void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
-  {
-    const DicomSeriesVolumeSlicer& source =
-      dynamic_cast<const DicomSeriesVolumeSlicer&>(message.GetOrigin());
-    
-    const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ?
-    std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
-                              boost::lexical_cast<std::string>(slice.GetFrame()));
-
-    LOG(WARNING) << "Layer ready: " << sliceKeyId;
-
-    // remove the slice from the preloading slices now that it has been fully loaded and it is referenced in the cache
-    if (preloadingInstances_.find(sliceKeyId) != preloadingInstances_.end())
-    {
-      preloadingInstances_.erase(sliceKeyId);
-    }
-
-    // re-emit original Layer message to observers
-    BroadcastMessage(message);
-  }
-}
--- a/Framework/SmartLoader.h	Tue May 21 13:27:54 2019 +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-2019 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 <map>
-
-#include "Layers/DicomSeriesVolumeSlicer.h"
-#include "Messages/IObservable.h"
-#include "Toolbox/OrthancApiClient.h"
-
-namespace Deprecated
-{
-  class SliceViewerWidget;
-
-  class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
-  {
-    class CachedSlice;
-
-  protected:
-    typedef std::map<std::string, boost::shared_ptr<SmartLoader::CachedSlice> > CachedSlices;
-    CachedSlices cachedSlices_;
-
-    typedef std::map<std::string, boost::shared_ptr<IVolumeSlicer> > PreloadingInstances;
-    PreloadingInstances preloadingInstances_;
-
-    OrthancStone::SliceImageQuality     imageQuality_;
-    OrthancApiClient&     orthancApiClient_;
-
-  public:
-    SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient);  // TODO: add maxPreloadStorageSizeInBytes
-
-//    void PreloadStudy(const std::string studyId);
-//    void PreloadSeries(const std::string seriesId);
-    void PreloadSlice(const std::string instanceId, unsigned int frame);
-
-    void SetImageQuality(OrthancStone::SliceImageQuality imageQuality) { imageQuality_ = imageQuality; }
-
-    void SetFrameInWidget(SliceViewerWidget& sliceViewer, size_t layerIndex, const std::string& instanceId, unsigned int frame);
-
-    void GetFirstInstanceIdForSeries(std::string& output, const std::string& seriesId);
-
-  private:
-    void OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
-    void OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message);
-    void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message);
-
-  };
-
-}
--- a/Framework/Toolbox/BaseWebService.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2018 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 "BaseWebService.h"
-
-#include <Core/OrthancException.h>
-#include "Framework/Messages/IObservable.h"
-#include "Platforms/Generic/IOracleCommand.h"
-#include <boost/shared_ptr.hpp>
-
-namespace Deprecated
-{
-
-
-  class BaseWebService::BaseWebServicePayload : public Orthanc::IDynamicObject
-  {
-  private:
-    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage> >   userSuccessHandler_;
-    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >     userFailureHandler_;
-    std::auto_ptr< Orthanc::IDynamicObject>                                   userPayload_;
-
-  public:
-    BaseWebServicePayload(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* userSuccessHandler,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* userFailureHandler,
-                          Orthanc::IDynamicObject* userPayload) :
-      userSuccessHandler_(userSuccessHandler),
-      userFailureHandler_(userFailureHandler),
-      userPayload_(userPayload)
-    {
-    }
-
-    void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const
-    {
-      if (userSuccessHandler_.get() != NULL)
-      {
-        // recreate a success message with the user payload
-        IWebService::HttpRequestSuccessMessage successMessage(message.GetUri(),
-                                                              message.GetAnswer(),
-                                                              message.GetAnswerSize(),
-                                                              message.GetAnswerHttpHeaders(),
-                                                              userPayload_.get());
-        userSuccessHandler_->Apply(successMessage);
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-    }
-
-    void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const
-    {
-      if (userFailureHandler_.get() != NULL)
-      {
-        // recreate a failure message with the user payload
-        IWebService::HttpRequestErrorMessage failureMessage(message.GetUri(),
-                                                            userPayload_.get());
-
-        userFailureHandler_->Apply(failureMessage);
-      }
-    }
-
-  };
-
-
-  void BaseWebService::GetAsync(const std::string& uri,
-                                const HttpHeaders& headers,
-                                Orthanc::IDynamicObject* payload  /* takes ownership */,
-                                OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                                OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-                                unsigned int timeoutInSeconds)
-  {
-    if (cache_.find(uri) == cache_.end())
-    {
-      GetAsyncInternal(uri, headers,
-                       new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered
-                       new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestSuccessMessage>
-                       (*this, &BaseWebService::CacheAndNotifyHttpSuccess),
-                       new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestErrorMessage>
-                       (*this, &BaseWebService::NotifyHttpError),
-                       timeoutInSeconds);
-    }
-    else
-    {
-      // create a command and "post" it to the Oracle so it is executed and commited "later"
-      NotifyHttpSuccessLater(cache_[uri], payload, successCallback);
-    }
-
-  }
-
-
-
-  void BaseWebService::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
-  {
-    if (message.HasPayload())
-    {
-      dynamic_cast<const BaseWebServicePayload&>(message.GetPayload()).HandleSuccess(message);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-
-  void BaseWebService::CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
-  {
-    cache_[message.GetUri()] = boost::shared_ptr<CachedHttpRequestSuccessMessage>(new CachedHttpRequestSuccessMessage(message));
-    NotifyHttpSuccess(message);
-  }
-
-  void BaseWebService::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message)
-  {
-    if (message.HasPayload())
-    {
-      dynamic_cast<const BaseWebServicePayload&>(message.GetPayload()).HandleFailure(message);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-
-
-
-
-}
--- a/Framework/Toolbox/BaseWebService.h	Tue May 21 13:27:54 2019 +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-2018 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 "IWebService.h"
-
-#include <string>
-#include <map>
-
-namespace Deprecated
-{
-  // This is an intermediate of IWebService that implements some caching on
-  // the HTTP GET requests
-  class BaseWebService : public IWebService, public OrthancStone::IObserver
-  {
-  public:
-    class CachedHttpRequestSuccessMessage
-    {
-    protected:
-      std::string                    uri_;
-      void*                          answer_;
-      size_t                         answerSize_;
-      IWebService::HttpHeaders       answerHeaders_;
-
-    public:
-      CachedHttpRequestSuccessMessage(const IWebService::HttpRequestSuccessMessage& message) :
-        uri_(message.GetUri()),
-        answerSize_(message.GetAnswerSize()),
-        answerHeaders_(message.GetAnswerHttpHeaders())
-      {
-        answer_ =  malloc(answerSize_);
-        memcpy(answer_, message.GetAnswer(), answerSize_);
-      }
-
-      ~CachedHttpRequestSuccessMessage()
-      {
-        free(answer_);
-      }
-
-      const std::string& GetUri() const
-      {
-        return uri_;
-      }
-
-      const void* GetAnswer() const
-      {
-        return answer_;
-      }
-
-      size_t GetAnswerSize() const
-      {
-        return answerSize_;
-      }
-
-      const IWebService::HttpHeaders&  GetAnswerHttpHeaders() const
-      {
-        return answerHeaders_;
-      }
-
-    };
-  protected:
-    class BaseWebServicePayload;
-
-    bool          cacheEnabled_;
-    std::map<std::string, boost::shared_ptr<CachedHttpRequestSuccessMessage> > cache_;  // TODO: this is currently an infinite cache !
-
-  public:
-
-    BaseWebService(OrthancStone::MessageBroker& broker) :
-      IWebService(broker),
-      IObserver(broker),
-      cacheEnabled_(true)
-    {
-    }
-
-    virtual ~BaseWebService()
-    {
-    }
-
-    virtual void EnableCache(bool enable)
-    {
-      cacheEnabled_ = enable;
-    }
-
-    virtual void GetAsync(const std::string& uri,
-                          const HttpHeaders& headers,
-                          Orthanc::IDynamicObject* payload  /* takes ownership */,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                          unsigned int timeoutInSeconds = 60);
-
-  protected:
-    virtual void GetAsyncInternal(const std::string& uri,
-                          const HttpHeaders& headers,
-                          Orthanc::IDynamicObject* payload  /* takes ownership */,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                          unsigned int timeoutInSeconds = 60) = 0;
-
-    virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
-                                        Orthanc::IDynamicObject* payload, // takes ownership
-                                        OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback) = 0;
-
-  private:
-    void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
-
-    void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message);
-
-    void CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
-
-  };
-}
--- a/Framework/Toolbox/DicomFrameConverter.cpp	Tue May 21 13:27:54 2019 +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-2019 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 "DicomFrameConverter.h"
-
-#include "LinearAlgebra.h"
-
-#include <Core/Images/Image.h>
-#include <Core/Images/ImageProcessing.h>
-#include <Core/OrthancException.h>
-#include <Core/Toolbox.h>
-
-namespace Deprecated
-{
-  static const Orthanc::DicomTag IMAGE_TAGS[] =
-  {
-    Orthanc::DICOM_TAG_BITS_STORED,
-    Orthanc::DICOM_TAG_DOSE_GRID_SCALING,
-    Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION,
-    Orthanc::DICOM_TAG_PIXEL_REPRESENTATION,
-    Orthanc::DICOM_TAG_RESCALE_INTERCEPT,
-    Orthanc::DICOM_TAG_RESCALE_SLOPE,
-    Orthanc::DICOM_TAG_WINDOW_CENTER,
-    Orthanc::DICOM_TAG_WINDOW_WIDTH
-  };
-
-  
-  void DicomFrameConverter::SetDefaultParameters()
-  {
-    isSigned_ = true;
-    isColor_ = false;
-    hasRescale_ = false;
-    rescaleIntercept_ = 0;
-    rescaleSlope_ = 1;
-    hasDefaultWindow_ = false;
-    defaultWindowCenter_ = 128;
-    defaultWindowWidth_ = 256;
-    expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
-  }
-
-
-  void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom)
-  {
-    SetDefaultParameters();
-
-    OrthancStone::Vector c, w;
-    if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) &&
-        OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) &&
-        c.size() > 0 && 
-        w.size() > 0)
-    {
-      hasDefaultWindow_ = true;
-      defaultWindowCenter_ = static_cast<float>(c[0]);
-      defaultWindowWidth_ = static_cast<float>(w[0]);
-    }
-
-    int32_t tmp;
-    if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION))
-    {
-      // Type 1 tag, must be present
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    isSigned_ = (tmp == 1);
-
-    double doseGridScaling;
-    bool isRTDose = false;
-    
-    if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) &&
-        dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE))
-    {
-      hasRescale_ = true;
-    }
-    else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING))
-    {
-      // This is for RT-DOSE
-      hasRescale_ = true;
-      isRTDose = true;
-      rescaleIntercept_ = 0;
-      rescaleSlope_ = doseGridScaling;
-
-      if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_BITS_STORED))
-      {
-        // Type 1 tag, must be present
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-      }
-
-      switch (tmp)
-      {
-        case 16:
-          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
-          break;
-
-        case 32:
-          expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32;
-          break;
-
-        default:
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-      }
-    }
-
-    std::string photometric;
-    if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false))
-    {
-      photometric = Orthanc::Toolbox::StripSpaces(photometric);
-    }
-    else
-    {
-      // Type 1 tag, must be present
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
-    }
-
-    photometric_ = Orthanc::StringToPhotometricInterpretation(photometric.c_str());
-    
-    isColor_ = (photometric != "MONOCHROME1" &&
-                photometric != "MONOCHROME2");
-
-    // TODO Add more checks, e.g. on the number of bytes per value
-    // (cf. DicomImageInformation.h in Orthanc)
-
-    if (!isRTDose)
-    {
-      if (isColor_)
-      {
-        expectedPixelFormat_ = Orthanc::PixelFormat_RGB24;
-      }
-      else if (isSigned_)
-      {
-        expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16;
-      }
-      else
-      {
-        expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16;
-      }
-    }
-  }
-
-  
-  void DicomFrameConverter::ReadParameters(const OrthancPlugins::IDicomDataset& dicom)
-  {
-    Orthanc::DicomMap converted;
-
-    for (size_t i = 0; i < sizeof(IMAGE_TAGS) / sizeof(Orthanc::DicomTag); i++)
-    {
-      OrthancPlugins::DicomTag tag(IMAGE_TAGS[i].GetGroup(), IMAGE_TAGS[i].GetElement());
-    
-      std::string value;
-      if (dicom.GetStringValue(value, tag))
-      {
-        converted.SetValue(IMAGE_TAGS[i], value, false);
-      }
-    }
-
-    ReadParameters(converted);
-  }
-    
-
-  void DicomFrameConverter::ConvertFrameInplace(std::auto_ptr<Orthanc::ImageAccessor>& source) const
-  {
-    assert(sizeof(float) == 4);
-
-    if (source.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    if (source->GetFormat() == GetExpectedPixelFormat() &&
-        source->GetFormat() == Orthanc::PixelFormat_RGB24)
-    {
-      // No conversion has to be done, check out (*)
-      return;
-    }
-    else
-    {
-      source.reset(ConvertFrame(*source));
-    }
-  }
-
-
-  Orthanc::ImageAccessor* DicomFrameConverter::ConvertFrame(const Orthanc::ImageAccessor& source) const
-  {
-    assert(sizeof(float) == 4);
-
-    Orthanc::PixelFormat sourceFormat = source.GetFormat();
-
-    if (sourceFormat != GetExpectedPixelFormat())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-    }
-
-    if (sourceFormat == Orthanc::PixelFormat_RGB24)
-    {
-      // This is the case of a color image. No conversion has to be done (*)
-      std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_RGB24, 
-                                                                 source.GetWidth(), 
-                                                                 source.GetHeight(),
-                                                                 false));
-      Orthanc::ImageProcessing::Copy(*converted, source);
-      return converted.release();
-    }
-    else
-    {
-      assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 ||
-             sourceFormat == Orthanc::PixelFormat_Grayscale32 ||
-             sourceFormat == Orthanc::PixelFormat_SignedGrayscale16);
-
-      // This is the case of a grayscale frame. Convert it to Float32.
-      std::auto_ptr<Orthanc::Image> converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, 
-                                                                 source.GetWidth(), 
-                                                                 source.GetHeight(),
-                                                                 false));
-      Orthanc::ImageProcessing::Convert(*converted, source);
-
-      // Correct rescale slope/intercept if need be
-      ApplyRescale(*converted, sourceFormat != Orthanc::PixelFormat_Grayscale32);
-      
-      return converted.release();
-    }
-  }
-
-
-  void DicomFrameConverter::ApplyRescale(Orthanc::ImageAccessor& image,
-                                         bool useDouble) const
-  {
-    if (image.GetFormat() != Orthanc::PixelFormat_Float32)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-    }
-    
-    if (hasRescale_)
-    {
-      for (unsigned int y = 0; y < image.GetHeight(); y++)
-      {
-        float* p = reinterpret_cast<float*>(image.GetRow(y));
-
-        if (useDouble)
-        {
-          // Slower, accurate implementation using double
-          for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
-          {
-            double value = static_cast<double>(*p);
-            *p = static_cast<float>(value * rescaleSlope_ + rescaleIntercept_);
-          }
-        }
-        else
-        {
-          // Fast, approximate implementation using float
-          for (unsigned int x = 0; x < image.GetWidth(); x++, p++)
-          {
-            *p = (*p) * static_cast<float>(rescaleSlope_) + static_cast<float>(rescaleIntercept_);
-          }
-        }
-      }
-    }
-  }
-
-  
-  double DicomFrameConverter::Apply(double x) const
-  {
-    return x * rescaleSlope_ + rescaleIntercept_;
-  }
-
-}
--- a/Framework/Toolbox/DicomFrameConverter.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 <Plugins/Samples/Common/IDicomDataset.h>
-#include <Core/DicomFormat/DicomMap.h>
-#include <Core/Images/ImageAccessor.h>
-
-#include <memory>
-
-namespace Deprecated
-{
-  /**
-   * This class is responsible for converting the pixel format of a
-   * DICOM frame coming from Orthanc, into a pixel format that is
-   * suitable for Stone, given the relevant DICOM tags:
-   * - Color frames will stay in the RGB24 format.
-   * - Grayscale frames will be converted to the Float32 format.
-   **/
-  class DicomFrameConverter
-  {
-  private:
-    bool    isSigned_;
-    bool    isColor_;
-    bool    hasRescale_;
-    double  rescaleIntercept_;
-    double  rescaleSlope_;
-    bool    hasDefaultWindow_;
-    double  defaultWindowCenter_;
-    double  defaultWindowWidth_;
-    
-    Orthanc::PhotometricInterpretation  photometric_;
-    Orthanc::PixelFormat                expectedPixelFormat_;
-
-    void SetDefaultParameters();
-
-  public:
-    DicomFrameConverter()
-    {
-      SetDefaultParameters();
-    }
-
-    ~DicomFrameConverter()
-    {
-      // TODO: check whether this dtor is called or not
-      // An MSVC warning explains that declaring an
-      // std::auto_ptr with a forward-declared type
-      // prevents its dtor from being called. Does not
-      // seem an issue here (only POD types inside), but
-      // definitely something to keep an eye on.
-      (void)0;
-    }
-
-    // AM: this is required to serialize/deserialize it
-    DicomFrameConverter(
-        bool isSigned,
-        bool isColor,
-        bool hasRescale,
-        double rescaleIntercept,
-        double rescaleSlope,
-        bool hasDefaultWindow,
-        double defaultWindowCenter,
-        double defaultWindowWidth,
-        Orthanc::PhotometricInterpretation photometric,
-        Orthanc::PixelFormat expectedPixelFormat
-        ):
-      isSigned_(isSigned),
-      isColor_(isColor),
-      hasRescale_(hasRescale),
-      rescaleIntercept_(rescaleIntercept),
-      rescaleSlope_(rescaleSlope),
-      hasDefaultWindow_(hasDefaultWindow),
-      defaultWindowCenter_(defaultWindowCenter),
-      defaultWindowWidth_(defaultWindowWidth),
-      photometric_(photometric),
-      expectedPixelFormat_(expectedPixelFormat)
-    {}
-
-    void GetParameters(bool& isSigned,
-                       bool& isColor,
-                       bool& hasRescale,
-                       double& rescaleIntercept,
-                       double& rescaleSlope,
-                       bool& hasDefaultWindow,
-                       double& defaultWindowCenter,
-                       double& defaultWindowWidth,
-                       Orthanc::PhotometricInterpretation& photometric,
-                       Orthanc::PixelFormat& expectedPixelFormat) const
-    {
-      isSigned = isSigned_;
-      isColor = isColor_;
-      hasRescale = hasRescale_;
-      rescaleIntercept = rescaleIntercept_;
-      rescaleSlope = rescaleSlope_;
-      hasDefaultWindow = hasDefaultWindow_;
-      defaultWindowCenter = defaultWindowCenter_;
-      defaultWindowWidth = defaultWindowWidth_;
-      photometric = photometric_;
-      expectedPixelFormat = expectedPixelFormat_;
-    }
-
-    Orthanc::PixelFormat GetExpectedPixelFormat() const
-    {
-      return expectedPixelFormat_;
-    }
-
-    Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const
-    {
-      return photometric_;
-    }
-
-    void ReadParameters(const Orthanc::DicomMap& dicom);
-
-    void ReadParameters(const OrthancPlugins::IDicomDataset& dicom);
-
-    bool HasDefaultWindow() const
-    {
-      return hasDefaultWindow_;
-    }
-    
-    double GetDefaultWindowCenter() const
-    {
-      return defaultWindowCenter_;
-    }
-    
-    double GetDefaultWindowWidth() const
-    {
-      return defaultWindowWidth_;
-    }
-
-    double GetRescaleIntercept() const
-    {
-      return rescaleIntercept_;
-    }
-
-    double GetRescaleSlope() const
-    {
-      return rescaleSlope_;
-    }
-
-    void ConvertFrameInplace(std::auto_ptr<Orthanc::ImageAccessor>& source) const;
-
-    Orthanc::ImageAccessor* ConvertFrame(const Orthanc::ImageAccessor& source) const;
-
-    void ApplyRescale(Orthanc::ImageAccessor& image,
-                      bool useDouble) const;
-
-    double Apply(double x) const;
-  };
-}
--- a/Framework/Toolbox/DownloadStack.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "DownloadStack.h"
-
-#include <Core/OrthancException.h>
-
-#include <cassert>
-
-namespace Deprecated
-{
-  bool DownloadStack::CheckInvariants() const
-  {
-    std::vector<bool> dequeued(nodes_.size(), true);
-
-    int i = firstNode_;
-    while (i != NIL)
-    {
-      const Node& node = nodes_[i];
-
-      dequeued[i] = false;
-
-      if (node.next_ != NIL &&
-          nodes_[node.next_].prev_ != i)
-      {
-        return false;
-      }
-
-      if (node.prev_ != NIL &&
-          nodes_[node.prev_].next_ != i)
-      {
-        return false;
-      }
-
-      i = nodes_[i].next_;
-    }
-
-    for (size_t i = 0; i < nodes_.size(); i++)
-    {
-      if (nodes_[i].dequeued_ != dequeued[i])
-      {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-
-  DownloadStack::DownloadStack(unsigned int size)
-  {
-    nodes_.resize(size);
-
-    if (size == 0)
-    {
-      firstNode_ = NIL;
-    }
-    else
-    {
-      for (size_t i = 0; i < size; i++)
-      {
-        nodes_[i].prev_ = static_cast<int>(i - 1);
-        nodes_[i].next_ = static_cast<int>(i + 1);
-        nodes_[i].dequeued_ = false;
-      }
-
-      nodes_.front().prev_ = NIL;
-      nodes_.back().next_ = NIL;
-      firstNode_ = 0;
-    }
-
-    assert(CheckInvariants());
-  }
-
-
-  DownloadStack::~DownloadStack()
-  {
-    assert(CheckInvariants());    
-  }
-
-
-  bool DownloadStack::Pop(unsigned int& value)
-  {
-    assert(CheckInvariants());
-
-    if (firstNode_ == NIL)
-    {
-      for (size_t i = 0; i < nodes_.size(); i++)
-      {
-        assert(nodes_[i].dequeued_);
-      }
-
-      return false;
-    }
-    else
-    {
-      assert(firstNode_ >= 0 && firstNode_ < static_cast<int>(nodes_.size()));
-      value = firstNode_;
-
-      Node& node = nodes_[firstNode_];
-      assert(node.prev_ == NIL);
-      assert(!node.dequeued_);
-
-      node.dequeued_ = true;
-      firstNode_ = node.next_;
-
-      if (firstNode_ != NIL)
-      {
-        nodes_[firstNode_].prev_ = NIL;
-      }
-
-      return true;
-    }
-  }
-
-
-  void DownloadStack::SetTopNodeInternal(unsigned int value)
-  {
-    assert(CheckInvariants());
-
-    Node& node = nodes_[value];
-
-    if (node.dequeued_)
-    {
-      // This node has already been processed by the download thread, nothing to do
-      return;
-    }
-
-    // Remove the node from the list
-    if (node.prev_ == NIL)
-    {
-      assert(firstNode_ == static_cast<int>(value));
-      
-      // This is already the top node in the list, nothing to do
-      return;
-    }
-
-    nodes_[node.prev_].next_ = node.next_;
-
-    if (node.next_ != NIL)
-    {
-      nodes_[node.next_].prev_ = node.prev_;
-    }
-
-    // Add back the node at the top of the list
-    assert(firstNode_ != NIL);
-
-    Node& old = nodes_[firstNode_];
-    assert(old.prev_ == NIL);
-    assert(!old.dequeued_);
-    node.prev_ = NIL;
-    node.next_ = firstNode_;
-    old.prev_ = value;
-
-    firstNode_ = value;
-  }
-
-  
-  void DownloadStack::SetTopNode(unsigned int value)
-  {
-    if (value >= nodes_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    SetTopNodeInternal(value);
-  }
-
-
-  void DownloadStack::SetTopNodePermissive(int value)
-  {
-    if (value >= 0 &&
-        value < static_cast<int>(nodes_.size()))
-    {
-      SetTopNodeInternal(value);
-    }
-  }
-}
--- a/Framework/Toolbox/DownloadStack.h	Tue May 21 13:27:54 2019 +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-2019 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 <vector>
-#include <boost/noncopyable.hpp>
-
-namespace Deprecated
-{
-  class DownloadStack : public boost::noncopyable
-  {
-  private:
-    static const int NIL = -1;
-
-    // This is a doubly-linked list
-    struct Node
-    {
-      int   next_;
-      int   prev_;
-      bool  dequeued_;
-    };
-
-    std::vector<Node>   nodes_;
-    int                 firstNode_;
-
-    bool CheckInvariants() const;
-
-    void SetTopNodeInternal(unsigned int value);  
-
-  public:
-    DownloadStack(unsigned int size);
-
-    ~DownloadStack();
-
-    bool Pop(unsigned int& value);
-
-    void SetTopNode(unsigned int value);  
-
-    void SetTopNodePermissive(int value);
-  };
-}
--- a/Framework/Toolbox/IDelayedCallExecutor.h	Tue May 21 13:27:54 2019 +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-2018 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/Messages/IObserver.h"
-#include "../../Framework/Messages/ICallable.h"
-
-#include <Core/IDynamicObject.h>
-#include <Core/Logging.h>
-
-#include <string>
-#include <map>
-
-namespace Deprecated
-{
-  // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript).
-  class IDelayedCallExecutor : public boost::noncopyable
-  {
-  protected:
-    OrthancStone::MessageBroker& broker_;
-    
-  public:
-    ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage);
-
-    IDelayedCallExecutor(OrthancStone::MessageBroker& broker) :
-      broker_(broker)
-    {
-    }
-
-    
-    virtual ~IDelayedCallExecutor()
-    {
-    }
-
-    
-    virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
-                          unsigned int timeoutInMs = 1000) = 0;
-  };
-}
--- a/Framework/Toolbox/IWebService.cpp	Tue May 21 13:27:54 2019 +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-2019 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 "IWebService.h"
-
-#include <Core/OrthancException.h>
-
-
-namespace Deprecated
-{
-  const Orthanc::IDynamicObject&
-  IWebService::HttpRequestSuccessMessage::GetPayload() const
-  {
-    if (HasPayload())
-    {
-      return *payload_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-    
-
-  const Orthanc::IDynamicObject&
-  IWebService::HttpRequestErrorMessage::GetPayload() const
-  {
-    if (HasPayload())
-    {
-      return *payload_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-}
--- a/Framework/Toolbox/IWebService.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/Messages/IObserver.h"
-#include "../../Framework/Messages/ICallable.h"
-
-#include <Core/IDynamicObject.h>
-#include <Core/Logging.h>
-
-#include <string>
-#include <map>
-
-namespace Deprecated
-{
-  // The IWebService performs HTTP requests.
-  // Since applications can run in native or WASM environment and, since
-  // in a WASM environment, the WebService is asynchronous, the IWebservice
-  // also implements an asynchronous interface: you must schedule a request
-  // and you'll be notified when the response/error is ready.
-  class IWebService : public boost::noncopyable
-  {
-  protected:
-    OrthancStone::MessageBroker& broker_;
-    
-  public:
-    typedef std::map<std::string, std::string> HttpHeaders;
-
-    class HttpRequestSuccessMessage : public OrthancStone::IMessage
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-
-    private:
-      const std::string&             uri_;
-      const void*                    answer_;
-      size_t                         answerSize_;
-      const HttpHeaders&             answerHeaders_;
-      const Orthanc::IDynamicObject* payload_;
-
-    public:
-      HttpRequestSuccessMessage(const std::string& uri,
-                                const void* answer,
-                                size_t answerSize,
-                                const HttpHeaders& answerHeaders,
-                                const Orthanc::IDynamicObject* payload) :
-        uri_(uri),
-        answer_(answer),
-        answerSize_(answerSize),
-        answerHeaders_(answerHeaders),
-        payload_(payload)
-      {
-      }
-
-      const std::string& GetUri() const
-      {
-        return uri_;
-      }
-
-      const void* GetAnswer() const
-      {
-        return answer_;
-      }
-
-      size_t GetAnswerSize() const
-      {
-        return answerSize_;
-      }
-
-      const HttpHeaders&  GetAnswerHttpHeaders() const
-      {
-        return answerHeaders_;
-      }
-
-      bool HasPayload() const
-      {
-        return payload_ != NULL;
-      }
-
-      const Orthanc::IDynamicObject& GetPayload() const;
-    };
-    
-
-    class HttpRequestErrorMessage : public OrthancStone::IMessage
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-
-    private:
-      const std::string&              uri_;
-      const Orthanc::IDynamicObject*  payload_;
-
-    public:
-      HttpRequestErrorMessage(const std::string& uri,
-                              const Orthanc::IDynamicObject* payload) :
-        uri_(uri),
-        payload_(payload)
-      {
-      }
-
-      const std::string& GetUri() const
-      {
-        return uri_;
-      }
-
-      bool HasPayload() const
-      {
-        return payload_ != NULL;
-      }
-
-      const Orthanc::IDynamicObject& GetPayload() const;
-    };
-
-
-    IWebService(OrthancStone::MessageBroker& broker) :
-      broker_(broker)
-    {
-    }
-
-    
-    virtual ~IWebService()
-    {
-    }
-
-    virtual void EnableCache(bool enable) = 0;
-    
-    virtual void GetAsync(const std::string& uri,
-                          const HttpHeaders& headers,
-                          Orthanc::IDynamicObject* payload  /* takes ownership */,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                          unsigned int timeoutInSeconds = 60) = 0;
-
-    virtual void PostAsync(const std::string& uri,
-                           const HttpHeaders& headers,
-                           const std::string& body,
-                           Orthanc::IDynamicObject* payload  /* takes ownership */,
-                           OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                           unsigned int timeoutInSeconds = 60) = 0;
-
-    virtual void DeleteAsync(const std::string& uri,
-                             const HttpHeaders& headers,
-                             Orthanc::IDynamicObject* payload  /* takes ownership */,
-                             OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
-                             OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                             unsigned int timeoutInSeconds = 60) = 0;
-  };
-}
--- a/Framework/Toolbox/OrthancApiClient.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "OrthancApiClient.h"
-
-#include "MessagingToolbox.h"
-#include "Framework/Toolbox/MessagingToolbox.h"
-
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const
-  {
-    if (HasPayload())
-    {
-      return *payload_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-  
-  
-  const Orthanc::IDynamicObject& OrthancApiClient::BinaryResponseReadyMessage::GetPayload() const
-  {
-    if (HasPayload())
-    {
-      return *payload_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-  
-  
-  const Orthanc::IDynamicObject& OrthancApiClient::EmptyResponseReadyMessage::GetPayload() const
-  {
-    if (HasPayload())
-    {
-      return *payload_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-  }
-  
-  
-  class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject
-  {
-  private:
-    std::auto_ptr< OrthancStone::MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
-    std::auto_ptr< OrthancStone::MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
-    std::auto_ptr< OrthancStone::MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
-    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
-    std::auto_ptr< Orthanc::IDynamicObject >                               userPayload_;
-
-    void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const
-    {
-      if (failureHandler_.get() != NULL)
-      {
-        failureHandler_->Apply(IWebService::HttpRequestErrorMessage
-                               (message.GetUri(), userPayload_.get()));
-      }
-    }
-    
-  public:
-    WebServicePayload(OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler,
-                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
-                      Orthanc::IDynamicObject* userPayload) :
-      emptyHandler_(handler),
-      failureHandler_(failureHandler),
-      userPayload_(userPayload)
-    {
-      if (handler == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-    }
-
-    WebServicePayload(OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler,
-                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
-                      Orthanc::IDynamicObject* userPayload) :
-      binaryHandler_(handler),
-      failureHandler_(failureHandler),
-      userPayload_(userPayload)
-    {
-      if (handler == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-    }
-
-    WebServicePayload(OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler,
-                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
-                      Orthanc::IDynamicObject* userPayload) :
-      jsonHandler_(handler),
-      failureHandler_(failureHandler),
-      userPayload_(userPayload)
-    {
-      if (handler == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-    }
-
-    void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const
-    {
-      if (emptyHandler_.get() != NULL)
-      {
-        emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage
-                             (message.GetUri(), userPayload_.get()));
-      }
-      else if (binaryHandler_.get() != NULL)
-      {
-        binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage
-                              (message.GetUri(), message.GetAnswer(),
-                               message.GetAnswerSize(), userPayload_.get()));
-      }
-      else if (jsonHandler_.get() != NULL)
-      {
-        Json::Value response;
-        if (OrthancStone::MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
-        {
-          jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage
-                              (message.GetUri(), response, userPayload_.get()));
-        }
-        else
-        {
-          NotifyConversionError(message);
-        }
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-    }
-
-    void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const
-    {
-      if (failureHandler_.get() != NULL)
-      {
-        failureHandler_->Apply(IWebService::HttpRequestErrorMessage
-                               (message.GetUri(), userPayload_.get()));
-      }
-    }
-  };
-
-
-  OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker,
-                                     IWebService& web,
-                                     const std::string& baseUrl) :
-    IObservable(broker),
-    IObserver(broker),
-    web_(web),
-    baseUrl_(baseUrl)
-  {
-  }
-
-
-  void OrthancApiClient::GetJsonAsync(
-      const std::string& uri,
-      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload)
-  {
-    IWebService::HttpHeaders emptyHeaders;
-    web_.GetAsync(baseUrl_ + uri,
-                  emptyHeaders,
-                  new WebServicePayload(successCallback, failureCallback, payload),
-                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                  (*this, &OrthancApiClient::NotifyHttpSuccess),
-                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                  (*this, &OrthancApiClient::NotifyHttpError));
-  }
-
-
-  void OrthancApiClient::GetBinaryAsync(
-      const std::string& uri,
-      const std::string& contentType,
-      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload)
-  {
-    IWebService::HttpHeaders headers;
-    headers["Accept"] = contentType;
-    GetBinaryAsync(uri, headers, successCallback, failureCallback, payload);
-  }
-
-  void OrthancApiClient::GetBinaryAsync(
-      const std::string& uri,
-      const IWebService::HttpHeaders& headers,
-      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload)
-  {
-    // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str());
-
-    web_.GetAsync(baseUrl_ + uri, headers,
-                  new WebServicePayload(successCallback, failureCallback, payload),
-                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                  (*this, &OrthancApiClient::NotifyHttpSuccess),
-                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                  (*this, &OrthancApiClient::NotifyHttpError));
-  }
-
-  
-  void OrthancApiClient::PostBinaryAsyncExpectJson(
-      const std::string& uri,
-      const std::string& body,
-      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload)
-  {
-    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
-                   new WebServicePayload(successCallback, failureCallback, payload),
-                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                   (*this, &OrthancApiClient::NotifyHttpSuccess),
-                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                   (*this, &OrthancApiClient::NotifyHttpError));
-
-  }
-
-  void OrthancApiClient::PostBinaryAsync(
-      const std::string& uri,
-      const std::string& body)
-  {
-    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, NULL, NULL, NULL);
-  }
-
-  void OrthancApiClient::PostBinaryAsync(
-      const std::string& uri,
-      const std::string& body,
-      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload   /* takes ownership */)
-  {
-    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
-                   new WebServicePayload(successCallback, failureCallback, payload),
-                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                   (*this, &OrthancApiClient::NotifyHttpSuccess),
-                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                   (*this, &OrthancApiClient::NotifyHttpError));
-  }
-
-  void OrthancApiClient::PostJsonAsyncExpectJson(
-      const std::string& uri,
-      const Json::Value& data,
-      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload)
-  {
-    std::string body;
-    OrthancStone::MessagingToolbox::JsonToString(body, data);
-    return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload);
-  }
-
-  void OrthancApiClient::PostJsonAsync(
-      const std::string& uri,
-      const Json::Value& data)
-  {
-    std::string body;
-    OrthancStone::MessagingToolbox::JsonToString(body, data);
-    return PostBinaryAsync(uri, body);
-  }
-
-  void OrthancApiClient::PostJsonAsync(
-      const std::string& uri,
-      const Json::Value& data,
-      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload   /* takes ownership */)
-  {
-    std::string body;
-    OrthancStone::MessagingToolbox::JsonToString(body, data);
-    return PostBinaryAsync(uri, body, successCallback, failureCallback, payload);
-  }
-
-  void OrthancApiClient::DeleteAsync(
-      const std::string& uri,
-      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
-      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
-      Orthanc::IDynamicObject* payload)
-  {
-    web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(),
-                     new WebServicePayload(successCallback, failureCallback, payload),
-                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                     (*this, &OrthancApiClient::NotifyHttpSuccess),
-                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                     (*this, &OrthancApiClient::NotifyHttpError));
-  }
-
-
-  void OrthancApiClient::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
-  {
-    if (message.HasPayload())
-    {
-      dynamic_cast<const WebServicePayload&>(message.GetPayload()).HandleSuccess(message);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-
-  void OrthancApiClient::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message)
-  {
-    if (message.HasPayload())
-    {
-      dynamic_cast<const WebServicePayload&>(message.GetPayload()).HandleFailure(message);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-}
--- a/Framework/Toolbox/OrthancApiClient.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,243 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include <boost/shared_ptr.hpp>
-#include <json/json.h>
-
-#include "IWebService.h"
-#include "../Messages/IObservable.h"
-#include "../Messages/Promise.h"
-
-namespace Deprecated
-{
-  class OrthancApiClient :
-      public OrthancStone::IObservable,
-      public OrthancStone::IObserver
-  {
-  public:
-    class JsonResponseReadyMessage : public OrthancStone::IMessage
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-
-    private:
-      const std::string&              uri_;
-      const Json::Value&              json_;
-      const Orthanc::IDynamicObject*  payload_;
-
-    public:
-      JsonResponseReadyMessage(const std::string& uri,
-                               const Json::Value& json,
-                               const Orthanc::IDynamicObject* payload) :
-        uri_(uri),
-        json_(json),
-        payload_(payload)
-      {
-      }
-
-      const std::string& GetUri() const
-      {
-        return uri_;
-      }
-
-      const Json::Value& GetJson() const
-      {
-        return json_;
-      }
-
-      bool HasPayload() const
-      {
-        return payload_ != NULL;
-      }
-
-      const Orthanc::IDynamicObject& GetPayload() const;
-    };
-    
-
-    class BinaryResponseReadyMessage : public OrthancStone::IMessage
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-
-    private:
-      const std::string&              uri_;
-      const void*                     answer_;
-      size_t                          answerSize_;
-      const Orthanc::IDynamicObject*  payload_;
-
-    public:
-      BinaryResponseReadyMessage(const std::string& uri,
-                                 const void* answer,
-                                 size_t answerSize,
-                                 const Orthanc::IDynamicObject* payload) :
-        uri_(uri),
-        answer_(answer),
-        answerSize_(answerSize),
-        payload_(payload)
-      {
-      }
-
-      const std::string& GetUri() const
-      {
-        return uri_;
-      }
-
-      const void* GetAnswer() const
-      {
-        return answer_;
-      }
-
-      size_t GetAnswerSize() const
-      {
-        return answerSize_;
-      }
-
-      bool HasPayload() const
-      {
-        return payload_ != NULL;
-      }
-
-      const Orthanc::IDynamicObject& GetPayload() const;
-    };
-
-
-    class EmptyResponseReadyMessage : public OrthancStone::IMessage
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-
-    private:
-      const std::string&              uri_;
-      const Orthanc::IDynamicObject*  payload_;
-
-    public:
-      EmptyResponseReadyMessage(const std::string& uri,
-                                const Orthanc::IDynamicObject* payload) :
-        uri_(uri),
-        payload_(payload)
-      {
-      }
-
-      const std::string& GetUri() const
-      {
-        return uri_;
-      }
-
-      bool HasPayload() const
-      {
-        return payload_ != NULL;
-      }
-
-      const Orthanc::IDynamicObject& GetPayload() const;
-    };
-
-    
-
-  private:
-    class WebServicePayload;
-
-  protected:
-    IWebService&  web_;
-    std::string   baseUrl_;
-
-  public:
-    OrthancApiClient(OrthancStone::MessageBroker& broker,
-                     IWebService& web,
-                     const std::string& baseUrl);
-    
-    virtual ~OrthancApiClient()
-    {
-    }
-
-    const std::string& GetBaseUrl() const {return baseUrl_;}
-
-    // schedule a GET request expecting a JSON response.
-    void GetJsonAsync(const std::string& uri,
-                      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
-                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                      Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    // schedule a GET request expecting a binary response.
-    void GetBinaryAsync(const std::string& uri,
-                        const std::string& contentType,
-                        OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
-                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    // schedule a GET request expecting a binary response.
-    void GetBinaryAsync(const std::string& uri,
-                        const IWebService::HttpHeaders& headers,
-                        OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
-                        OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    // schedule a POST request expecting a JSON response.
-    void PostBinaryAsyncExpectJson(const std::string& uri,
-                                   const std::string& body,
-                                   OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
-                                   OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                                   Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    // schedule a POST request expecting a JSON response.
-    void PostJsonAsyncExpectJson(const std::string& uri,
-                                 const Json::Value& data,
-                                 OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
-                                 OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                                 Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    // schedule a POST request and don't mind the response.
-    void PostJsonAsync(const std::string& uri,
-                       const Json::Value& data);
-
-    // schedule a POST request and don't expect any response.
-    void PostJsonAsync(const std::string& uri,
-                       const Json::Value& data,
-                       OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
-                       OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                       Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-
-    // schedule a POST request and don't mind the response.
-    void PostBinaryAsync(const std::string& uri,
-                         const std::string& body);
-
-    // schedule a POST request and don't expect any response.
-    void PostBinaryAsync(const std::string& uri,
-                         const std::string& body,
-                         OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
-                         OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                         Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    // schedule a DELETE request expecting an empty response.
-    void DeleteAsync(const std::string& uri,
-                     OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
-                     OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
-                     Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
-
-    void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message);
-
-    void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message);
-
-  private:
-    void HandleFromCache(const std::string& uri,
-                         const IWebService::HttpHeaders& headers,
-                         Orthanc::IDynamicObject* payload /* takes ownership */);
-  };
-}
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,904 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "OrthancSlicesLoader.h"
-
-#include "MessagingToolbox.h"
-
-#include <Core/Compression/GzipCompressor.h>
-#include <Core/Endianness.h>
-#include <Core/Images/Image.h>
-#include <Core/Images/ImageProcessing.h>
-#include <Core/Images/JpegReader.h>
-#include <Core/Images/PngReader.h>
-#include <Core/Images/PamReader.h>
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <Core/Toolbox.h>
-#include <Plugins/Samples/Common/FullOrthancDataset.h>
-
-#include <boost/lexical_cast.hpp>
-
-
-
-/**
- * TODO This is a SLOW implementation of base64 decoding, because
- * "Orthanc::Toolbox::DecodeBase64()" does not work properly with
- * WASM. UNDERSTAND WHY.
- * https://stackoverflow.com/a/34571089/881731
- **/
-static std::string base64_decode(const std::string &in)
-{
-  std::string out;
-  
-  std::vector<int> T(256,-1);
-  for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
-  
-  int val=0, valb=-8;
-  for (size_t i = 0; i < in.size(); i++) {
-    unsigned char c = in[i];
-    if (T[c] == -1) break;
-    val = (val<<6) + T[c];
-    valb += 6;
-    if (valb>=0) {
-      out.push_back(char((val>>valb)&0xFF));
-      valb-=8;
-    }
-  }
-  return out;
-}
-
-
-
-namespace Deprecated
-{
-  class OrthancSlicesLoader::Operation : public Orthanc::IDynamicObject
-  {
-  private:
-    Mode               mode_;
-    unsigned int       frame_;
-    unsigned int       sliceIndex_;
-    const Slice*       slice_;
-    std::string        instanceId_;
-    OrthancStone::SliceImageQuality  quality_;
-
-    Operation(Mode mode) :
-      mode_(mode)
-    {
-    }
-
-  public:
-    Mode GetMode() const
-    {
-      return mode_;
-    }
-
-    OrthancStone::SliceImageQuality GetQuality() const
-    {
-      assert(mode_ == Mode_LoadImage ||
-             mode_ == Mode_LoadRawImage);
-      return quality_;
-    }
-
-    unsigned int GetSliceIndex() const
-    {
-      assert(mode_ == Mode_LoadImage ||
-             mode_ == Mode_LoadRawImage);
-      return sliceIndex_;
-    }
-
-    const Slice& GetSlice() const
-    {
-      assert(mode_ == Mode_LoadImage ||
-             mode_ == Mode_LoadRawImage);
-      assert(slice_ != NULL);
-      return *slice_;
-    }
-
-    unsigned int GetFrame() const
-    {
-      assert(mode_ == Mode_FrameGeometry);
-      return frame_;
-    }
-
-    const std::string& GetInstanceId() const
-    {
-      assert(mode_ == Mode_FrameGeometry ||
-             mode_ == Mode_InstanceGeometry);
-      return instanceId_;
-    }
-
-    static Operation* DownloadInstanceGeometry(const std::string& instanceId)
-    {
-      std::auto_ptr<Operation> operation(new Operation(Mode_InstanceGeometry));
-      operation->instanceId_ = instanceId;
-      return operation.release();
-    }
-
-    static Operation* DownloadFrameGeometry(const std::string& instanceId,
-                                            unsigned int frame)
-    {
-      std::auto_ptr<Operation> operation(new Operation(Mode_FrameGeometry));
-      operation->instanceId_ = instanceId;
-      operation->frame_ = frame;
-      return operation.release();
-    }
-
-    static Operation* DownloadSliceImage(unsigned int  sliceIndex,
-                                         const Slice&  slice,
-                                         OrthancStone::SliceImageQuality quality)
-    {
-      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadImage));
-      tmp->sliceIndex_ = sliceIndex;
-      tmp->slice_ = &slice;
-      tmp->quality_ = quality;
-      return tmp.release();
-    }
-
-    static Operation* DownloadSliceRawImage(unsigned int  sliceIndex,
-                                            const Slice&  slice)
-    {
-      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadRawImage));
-      tmp->sliceIndex_ = sliceIndex;
-      tmp->slice_ = &slice;
-      tmp->quality_ = OrthancStone::SliceImageQuality_InternalRaw;
-      return tmp.release();
-    }
-
-    static Operation* DownloadDicomFile(const Slice&  slice)
-    {
-      std::auto_ptr<Operation> tmp(new Operation(Mode_LoadDicomFile));
-      tmp->slice_ = &slice;
-      return tmp.release();
-    }
-
-  };
-
-  void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation,
-                                                    const Orthanc::ImageAccessor& image)
-  {
-    OrthancSlicesLoader::SliceImageReadyMessage msg
-      (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality());
-    BroadcastMessage(msg);
-  }
-  
-  
-  void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation)
-  {
-    OrthancSlicesLoader::SliceImageErrorMessage msg
-      (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality());
-    BroadcastMessage(msg);
-  }
-  
-  
-  void OrthancSlicesLoader::SortAndFinalizeSlices()
-  {
-    bool ok = slices_.Sort();
-    
-    state_ = State_GeometryReady;
-    
-    if (ok)
-    {
-      LOG(INFO) << "Loaded a series with " << slices_.GetSlicesCount() << " slice(s)";
-      BroadcastMessage(SliceGeometryReadyMessage(*this));
-    }
-    else
-    {
-      LOG(ERROR) << "This series is empty";
-      BroadcastMessage(SliceGeometryErrorMessage(*this));
-    }
-  }
-  
-  void OrthancSlicesLoader::OnGeometryError(const IWebService::HttpRequestErrorMessage& message)
-  {
-    BroadcastMessage(SliceGeometryErrorMessage(*this));
-    state_ = State_Error;
-  }
-
-  void OrthancSlicesLoader::OnSliceImageError(const IWebService::HttpRequestErrorMessage& message)
-  {
-    NotifySliceImageError(dynamic_cast<const Operation&>(message.GetPayload()));
-    state_ = State_Error;
-  }
-
-  void OrthancSlicesLoader::ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& series = message.GetJson();
-    Json::Value::Members instances = series.getMemberNames();
-    
-    slices_.Reserve(instances.size());
-    
-    for (size_t i = 0; i < instances.size(); i++)
-    {
-      OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]);
-      
-      Orthanc::DicomMap dicom;
-      OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
-      
-      unsigned int frames;
-      if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
-      {
-        frames = 1;
-      }
-      
-      for (unsigned int frame = 0; frame < frames; frame++)
-      {
-        std::auto_ptr<Slice> slice(new Slice);
-        if (slice->ParseOrthancFrame(dicom, instances[i], frame))
-        {
-          OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
-          slices_.AddSlice(geometry, slice.release());
-        }
-        else
-        {
-          LOG(WARNING) << "Skipping invalid frame " << frame << " within instance " << instances[i];
-        }
-      }
-    }
-    
-    SortAndFinalizeSlices();
-  }
-  
-  void OrthancSlicesLoader::ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& tags = message.GetJson();
-    const std::string& instanceId = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetInstanceId();
-
-    OrthancPlugins::FullOrthancDataset dataset(tags);
-    
-    Orthanc::DicomMap dicom;
-    OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
-
-    unsigned int frames;
-    if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
-    {
-      frames = 1;
-    }
-    
-    LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)";
-    
-    for (unsigned int frame = 0; frame < frames; frame++)
-    {
-      std::auto_ptr<Slice> slice(new Slice);
-      if (slice->ParseOrthancFrame(dicom, instanceId, frame))
-      {
-        OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
-        slices_.AddSlice(geometry, slice.release());
-      }
-      else
-      {
-        LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId;
-        BroadcastMessage(SliceGeometryErrorMessage(*this));
-        return;
-      }
-    }
-    
-    SortAndFinalizeSlices();
-  }
-  
-  
-  void OrthancSlicesLoader::ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& tags = message.GetJson();
-    const std::string& instanceId = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetInstanceId();
-    unsigned int frame = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetFrame();
-
-    OrthancPlugins::FullOrthancDataset dataset(tags);
-    
-    state_ = State_GeometryReady;
-    
-    Orthanc::DicomMap dicom;
-    OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset);
-    
-    std::auto_ptr<Slice> slice(new Slice);
-    if (slice->ParseOrthancFrame(dicom, instanceId, frame))
-    {
-      LOG(INFO) << "Loaded instance geometry " << instanceId;
-
-      OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry();
-      slices_.AddSlice(geometry, slice.release());
-      
-      BroadcastMessage(SliceGeometryReadyMessage(*this));
-    }
-    else
-    {
-      LOG(WARNING) << "Skipping invalid instance " << instanceId;
-      BroadcastMessage(SliceGeometryErrorMessage(*this));
-    }
-  }
-  
-  
-  void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message)
-  {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
-    std::auto_ptr<Orthanc::ImageAccessor>  image;
-    
-    try
-    {
-      image.reset(new Orthanc::PngReader);
-      dynamic_cast<Orthanc::PngReader&>(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize());
-    }
-    catch (Orthanc::OrthancException&)
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-    
-    if (image->GetWidth() != operation.GetSlice().GetWidth() ||
-        image->GetHeight() != operation.GetSlice().GetHeight())
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-
-    if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() ==
-        Orthanc::PixelFormat_SignedGrayscale16)
-    {
-      if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
-      {
-        image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
-      }
-      else
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-    }
-    
-    NotifySliceImageSuccess(operation, *image);
-  }
-  
-  void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message)
-  {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
-    std::auto_ptr<Orthanc::ImageAccessor>  image;
-
-    try
-    {
-      image.reset(new Orthanc::PamReader);
-      dynamic_cast<Orthanc::PamReader&>(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize());
-    }
-    catch (Orthanc::OrthancException&)
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-
-    if (image->GetWidth() != operation.GetSlice().GetWidth() ||
-        image->GetHeight() != operation.GetSlice().GetHeight())
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-
-    if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() ==
-        Orthanc::PixelFormat_SignedGrayscale16)
-    {
-      if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16)
-      {
-        image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16);
-      }
-      else
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-    }
-
-    NotifySliceImageSuccess(operation, *image);
-  }
-
-
-  void OrthancSlicesLoader::ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
-
-    const Json::Value& encoded = message.GetJson();
-    if (encoded.type() != Json::objectValue ||
-        !encoded.isMember("Orthanc") ||
-        encoded["Orthanc"].type() != Json::objectValue)
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-    
-    const Json::Value& info = encoded["Orthanc"];
-    if (!info.isMember("PixelData") ||
-        !info.isMember("Stretched") ||
-        !info.isMember("Compression") ||
-        info["Compression"].type() != Json::stringValue ||
-        info["PixelData"].type() != Json::stringValue ||
-        info["Stretched"].type() != Json::booleanValue ||
-        info["Compression"].asString() != "Jpeg")
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-    
-    bool isSigned = false;
-    bool isStretched = info["Stretched"].asBool();
-    
-    if (info.isMember("IsSigned"))
-    {
-      if (info["IsSigned"].type() != Json::booleanValue)
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-      else
-      {
-        isSigned = info["IsSigned"].asBool();
-      }
-    }
-    
-    std::auto_ptr<Orthanc::ImageAccessor> reader;
-    
-    {
-      std::string jpeg;
-      //Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString());
-      jpeg = base64_decode(info["PixelData"].asString());
-      
-      try
-      {
-        reader.reset(new Orthanc::JpegReader);
-        dynamic_cast<Orthanc::JpegReader&>(*reader).ReadFromMemory(jpeg);
-      }
-      catch (Orthanc::OrthancException&)
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-    }
-    
-    Orthanc::PixelFormat expectedFormat =
-      operation.GetSlice().GetConverter().GetExpectedPixelFormat();
-    
-    if (reader->GetFormat() == Orthanc::PixelFormat_RGB24)  // This is a color image
-    {
-      if (expectedFormat != Orthanc::PixelFormat_RGB24)
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-      
-      if (isSigned || isStretched)
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-      else
-      {
-        NotifySliceImageSuccess(operation, *reader);
-        return;
-      }
-    }
-    
-    if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8)
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-    
-    if (!isStretched)
-    {
-      if (expectedFormat != reader->GetFormat())
-      {
-        NotifySliceImageError(operation);
-        return;
-      }
-      else
-      {
-        NotifySliceImageSuccess(operation, *reader);
-        return;
-      }
-    }
-    
-    int32_t stretchLow = 0;
-    int32_t stretchHigh = 0;
-    
-    if (!info.isMember("StretchLow") ||
-        !info.isMember("StretchHigh") ||
-        info["StretchLow"].type() != Json::intValue ||
-        info["StretchHigh"].type() != Json::intValue)
-    {
-      NotifySliceImageError(operation);
-      return;
-    }
-    
-    stretchLow = info["StretchLow"].asInt();
-    stretchHigh = info["StretchHigh"].asInt();
-    
-    if (stretchLow < -32768 ||
-        stretchHigh > 65535 ||
-        (stretchLow < 0 && stretchHigh > 32767))
-    {
-      // This range cannot be represented with a uint16_t or an int16_t
-      NotifySliceImageError(operation);
-      return;
-    }
-    
-    // Decode a grayscale JPEG 8bpp image coming from the Web viewer
-    std::auto_ptr<Orthanc::ImageAccessor> image
-      (new Orthanc::Image(expectedFormat, reader->GetWidth(), reader->GetHeight(), false));
-
-    Orthanc::ImageProcessing::Convert(*image, *reader);
-    reader.reset();
-    
-    float scaling = static_cast<float>(stretchHigh - stretchLow) / 255.0f;
-    
-    if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling))
-    {
-      float offset = static_cast<float>(stretchLow) / scaling;
-      Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
-    }
-    
-    NotifySliceImageSuccess(operation, *image);
-  }
-
-
-  class StringImage : public Orthanc::ImageAccessor
-  {
-  private:
-    std::string  buffer_;
-    
-  public:
-    StringImage(Orthanc::PixelFormat format,
-                unsigned int width,
-                unsigned int height,
-                std::string& buffer)
-    {
-      if (buffer.size() != Orthanc::GetBytesPerPixel(format) * width * height)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
-      }
-      
-      buffer_.swap(buffer);  // The source buffer is now empty
-      
-      void* data = (buffer_.empty() ? NULL : &buffer_[0]);
-      
-      AssignWritable(format, width, height,
-                     Orthanc::GetBytesPerPixel(format) * width, data);
-    }
-  };
-  
-  void OrthancSlicesLoader::ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message)
-  {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
-    Orthanc::GzipCompressor compressor;
-    
-    std::string raw;
-    compressor.Uncompress(raw, message.GetAnswer(), message.GetAnswerSize());
-    
-    const Orthanc::DicomImageInformation& info = operation.GetSlice().GetImageInformation();
-    
-    if (info.GetBitsAllocated() == 32 &&
-        info.GetBitsStored() == 32 &&
-        info.GetHighBit() == 31 &&
-        info.GetChannelCount() == 1 &&
-        !info.IsSigned() &&
-        info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 &&
-        raw.size() == info.GetWidth() * info.GetHeight() * 4)
-    {
-      // This is the case of RT-DOSE (uint32_t values)
-      
-      std::auto_ptr<Orthanc::ImageAccessor> image
-        (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(),
-                         info.GetHeight(), raw));
-      
-      // TODO - Only for big endian
-      for (unsigned int y = 0; y < image->GetHeight(); y++)
-      {
-        uint32_t *p = reinterpret_cast<uint32_t*>(image->GetRow(y));
-        for (unsigned int x = 0; x < image->GetWidth(); x++, p++)
-        {
-          *p = le32toh(*p);
-        }
-      }
-      
-      NotifySliceImageSuccess(operation, *image);
-    }
-    else if (info.GetBitsAllocated() == 16 &&
-             info.GetBitsStored() == 16 &&
-             info.GetHighBit() == 15 &&
-             info.GetChannelCount() == 1 &&
-             !info.IsSigned() &&
-             info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 &&
-             raw.size() == info.GetWidth() * info.GetHeight() * 2)
-    {
-      std::auto_ptr<Orthanc::ImageAccessor> image
-        (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(),
-                         info.GetHeight(), raw));
-      
-      // TODO - Big endian ?
-      
-      NotifySliceImageSuccess(operation, *image);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-    }
-
-  }
-  
-  
-  OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
-                                           OrthancApiClient& orthanc) :
-    OrthancStone::IObservable(broker),
-    OrthancStone::IObserver(broker),
-    orthanc_(orthanc),
-    state_(State_Initialization)
-  {
-  }
-  
-  
-  void OrthancSlicesLoader::ScheduleLoadSeries(const std::string& seriesId)
-  {
-    if (state_ != State_Initialization)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      state_ = State_LoadingGeometry;
-      orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags",
-                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSeriesGeometry),
-                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
-                            NULL);
-    }
-  }
-  
-  void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId)
-  {
-    if (state_ != State_Initialization)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      state_ = State_LoadingGeometry;
-      
-      // Tag "3004-000c" is "Grid Frame Offset Vector", which is
-      // mandatory to read RT DOSE, but is too long to be returned by default
-      orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c",
-                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseInstanceGeometry),
-                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
-                            Operation::DownloadInstanceGeometry(instanceId));
-    }
-  }
-  
-  
-  void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId,
-                                              unsigned int frame)
-  {
-    if (state_ != State_Initialization)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      state_ = State_LoadingGeometry;
-
-      orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags",
-                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseFrameGeometry),
-                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
-                            Operation::DownloadFrameGeometry(instanceId, frame));
-    }
-  }
-  
-  
-  bool OrthancSlicesLoader::IsGeometryReady() const
-  {
-    return state_ == State_GeometryReady;
-  }
-  
-  
-  size_t OrthancSlicesLoader::GetSlicesCount() const
-  {
-    if (state_ != State_GeometryReady)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    
-    return slices_.GetSlicesCount();
-  }
-  
-  
-  const Slice& OrthancSlicesLoader::GetSlice(size_t index) const
-  {
-    if (state_ != State_GeometryReady)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    return dynamic_cast<const Slice&>(slices_.GetSlicePayload(index));
-  }
-  
-  
-  bool OrthancSlicesLoader::LookupSlice(size_t& index,
-                                        const OrthancStone::CoordinateSystem3D& plane) const
-  {
-    if (state_ != State_GeometryReady)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    double distance;
-    return (slices_.LookupClosestSlice(index, distance, plane) &&
-            distance <= GetSlice(index).GetThickness() / 2.0);
-  }
-  
-  
-  void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice,
-                                                  size_t index)
-  {
-    std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
-                       boost::lexical_cast<std::string>(slice.GetFrame()));
-    
-    switch (slice.GetConverter().GetExpectedPixelFormat())
-    {
-      case Orthanc::PixelFormat_RGB24:
-        uri += "/preview";
-        break;
-      
-      case Orthanc::PixelFormat_Grayscale16:
-        uri += "/image-uint16";
-        break;
-      
-      case Orthanc::PixelFormat_SignedGrayscale16:
-        uri += "/image-int16";
-        break;
-      
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-    
-    orthanc_.GetBinaryAsync(uri, "image/png",
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        OrthancApiClient::BinaryResponseReadyMessage>
-          (*this, &OrthancSlicesLoader::ParseSliceImagePng),
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        IWebService::HttpRequestErrorMessage>
-          (*this, &OrthancSlicesLoader::OnSliceImageError),
-      Operation::DownloadSliceImage(
-        static_cast<unsigned int>(index), slice, OrthancStone::SliceImageQuality_FullPng));
-}
-  
-  void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice,
-                                                  size_t index)
-  {
-    std::string uri = 
-      ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
-      boost::lexical_cast<std::string>(slice.GetFrame()));
-
-    switch (slice.GetConverter().GetExpectedPixelFormat())
-    {
-      case Orthanc::PixelFormat_RGB24:
-        uri += "/preview";
-        break;
-
-      case Orthanc::PixelFormat_Grayscale16:
-        uri += "/image-uint16";
-        break;
-
-      case Orthanc::PixelFormat_SignedGrayscale16:
-        uri += "/image-int16";
-        break;
-
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap",
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        OrthancApiClient::BinaryResponseReadyMessage>
-          (*this, &OrthancSlicesLoader::ParseSliceImagePam),
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        IWebService::HttpRequestErrorMessage>
-          (*this, &OrthancSlicesLoader::OnSliceImageError),
-      Operation::DownloadSliceImage(static_cast<unsigned int>(index), 
-                                    slice, OrthancStone::SliceImageQuality_FullPam));
-  }
-
-
-  
-  void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice,
-                                                   size_t index,
-                                                   OrthancStone::SliceImageQuality quality)
-  {
-    unsigned int value;
-    
-    switch (quality)
-    {
-      case OrthancStone::SliceImageQuality_Jpeg50:
-        value = 50;
-        break;
-
-      case OrthancStone::SliceImageQuality_Jpeg90:
-        value = 90;
-        break;
-
-      case OrthancStone::SliceImageQuality_Jpeg95:
-        value = 95;
-        break;
-      
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-    
-    // This requires the official Web viewer plugin to be installed!
-    std::string uri = ("/web-viewer/instances/jpeg" +
-                       boost::lexical_cast<std::string>(value) +
-                       "-" + slice.GetOrthancInstanceId() + "_" +
-                       boost::lexical_cast<std::string>(slice.GetFrame()));
-
-    orthanc_.GetJsonAsync(uri,
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        OrthancApiClient::JsonResponseReadyMessage>
-          (*this, &OrthancSlicesLoader::ParseSliceImageJpeg),
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        IWebService::HttpRequestErrorMessage>
-          (*this, &OrthancSlicesLoader::OnSliceImageError),
-        Operation::DownloadSliceImage(
-          static_cast<unsigned int>(index), slice, quality));
-  }
-  
-  
-  
-  void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index,
-                                                   OrthancStone::SliceImageQuality quality)
-  {
-    if (state_ != State_GeometryReady)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    
-    const Slice& slice = GetSlice(index);
-    
-    if (slice.HasOrthancDecoding())
-    {
-      switch (quality)
-      {
-        case OrthancStone::SliceImageQuality_FullPng:
-          ScheduleSliceImagePng(slice, index);
-          break;
-        case OrthancStone::SliceImageQuality_FullPam:
-          ScheduleSliceImagePam(slice, index);
-          break;
-        default:
-          ScheduleSliceImageJpeg(slice, index, quality);
-      }
-    }
-    else
-    {
-      std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
-                         boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz");
-      orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(),
-        new OrthancStone::Callable<OrthancSlicesLoader, 
-          OrthancApiClient::BinaryResponseReadyMessage>
-            (*this, &OrthancSlicesLoader::ParseSliceRawImage),
-        new OrthancStone::Callable<OrthancSlicesLoader,
-          IWebService::HttpRequestErrorMessage>
-            (*this, &OrthancSlicesLoader::OnSliceImageError),
-        Operation::DownloadSliceRawImage(
-          static_cast<unsigned int>(index), slice));
-    }
-  }
-}
--- a/Framework/Toolbox/OrthancSlicesLoader.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,209 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "../Messages/IObservable.h"
-#include "../StoneEnumerations.h"
-#include "IWebService.h"
-#include "OrthancApiClient.h"
-#include "SlicesSorter.h"
-#include "Slice.h"
-
-#include <Core/Images/Image.h>
-
-
-namespace Deprecated
-{
-  class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
-  {
-  public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryErrorMessage, OrthancSlicesLoader);
-
-    
-    class SliceImageReadyMessage : public OrthancStone::OriginMessage<OrthancSlicesLoader>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      unsigned int                   sliceIndex_;
-      const Slice&                   slice_;
-      const Orthanc::ImageAccessor&  image_;
-      OrthancStone::SliceImageQuality  effectiveQuality_;
-
-    public:
-      SliceImageReadyMessage(const OrthancSlicesLoader& origin,
-                             unsigned int sliceIndex,
-                             const Slice& slice,
-                             const Orthanc::ImageAccessor& image,
-                             OrthancStone::SliceImageQuality effectiveQuality) :
-        OriginMessage(origin),
-        sliceIndex_(sliceIndex),
-        slice_(slice),
-        image_(image),
-        effectiveQuality_(effectiveQuality)
-      {
-      }
-
-      unsigned int GetSliceIndex() const
-      {
-        return sliceIndex_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-
-      const Orthanc::ImageAccessor& GetImage() const
-      {
-        return image_;
-      }
-
-      OrthancStone::SliceImageQuality GetEffectiveQuality() const
-      {
-        return effectiveQuality_;
-      }        
-    };
-    
-
-    class SliceImageErrorMessage : public OrthancStone::OriginMessage<OrthancSlicesLoader>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      const Slice&       slice_;
-      unsigned int       sliceIndex_;
-      OrthancStone::SliceImageQuality  effectiveQuality_;
-
-    public:
-      SliceImageErrorMessage(const OrthancSlicesLoader& origin,
-                             unsigned int sliceIndex,
-                             const Slice& slice,
-                             OrthancStone::SliceImageQuality effectiveQuality) :
-        OriginMessage(origin),
-        slice_(slice),
-        sliceIndex_(sliceIndex),
-        effectiveQuality_(effectiveQuality)
-      {
-      }
-      unsigned int GetSliceIndex() const
-      {
-        return sliceIndex_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-
-      OrthancStone::SliceImageQuality GetEffectiveQuality() const
-      {
-        return effectiveQuality_;
-      }        
-    };
-    
-  private:
-    enum State
-    {
-      State_Error,
-      State_Initialization,
-      State_LoadingGeometry,
-      State_GeometryReady
-    };
-    
-    enum Mode
-    {
-      Mode_SeriesGeometry,
-      Mode_InstanceGeometry,
-      Mode_FrameGeometry,
-      Mode_LoadImage,
-      Mode_LoadRawImage,
-      Mode_LoadDicomFile
-    };
-
-    class Operation;
-
-    OrthancApiClient&  orthanc_;
-    State         state_;
-    OrthancStone::SlicesSorter  slices_;
-
-    void NotifySliceImageSuccess(const Operation& operation,
-                                 const Orthanc::ImageAccessor& image);
-    
-    void NotifySliceImageError(const Operation& operation);
-
-    void OnGeometryError(const IWebService::HttpRequestErrorMessage& message);
-
-    void OnSliceImageError(const IWebService::HttpRequestErrorMessage& message);
-
-    void ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message);
-
-    void ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message);
-
-    void ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message);
-
-    void ScheduleSliceImagePng(const Slice& slice,
-                               size_t index);
-
-    void ScheduleSliceImagePam(const Slice& slice,
-                               size_t index);
-
-    void ScheduleSliceImageJpeg(const Slice& slice,
-                                size_t index,
-                                OrthancStone::SliceImageQuality quality);
-
-    void SortAndFinalizeSlices();
-    
-  public:
-    OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
-                        //ISliceLoaderObserver& callback,
-                        OrthancApiClient& orthancApi);
-
-    void ScheduleLoadSeries(const std::string& seriesId);
-
-    void ScheduleLoadInstance(const std::string& instanceId);
-
-    void ScheduleLoadFrame(const std::string& instanceId,
-                           unsigned int frame);
-
-    bool IsGeometryReady() const;
-
-    size_t GetSlicesCount() const;
-
-    const Slice& GetSlice(size_t index) const;
-
-    bool LookupSlice(size_t& index,
-                     const OrthancStone::CoordinateSystem3D& plane) const;
-
-    void ScheduleLoadSliceImage(size_t index,
-                                OrthancStone::SliceImageQuality requestedQuality);
-  };
-}
--- a/Framework/Toolbox/Slice.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,367 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "Slice.h"
-
-#include "../StoneEnumerations.h"
-#include "GeometryToolbox.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <Core/Toolbox.h>
-
-#include <boost/lexical_cast.hpp>
-
-namespace Deprecated
-{
-  static bool ParseDouble(double& target,
-                          const std::string& source)
-  {
-    try
-    {
-      target = boost::lexical_cast<double>(source);
-      return true;
-    }
-    catch (boost::bad_lexical_cast&)
-    {
-      return false;
-    }
-  }
-
-  Slice* Slice::Clone() const
-  {
-    std::auto_ptr<Slice> target(new Slice());
-
-    target->type_ = type_;
-    target->orthancInstanceId_ = orthancInstanceId_;
-    target->sopClassUid_ = sopClassUid_;
-    target->frame_ = frame_;
-    target->frameCount_ = frameCount_;
-    target->geometry_ = geometry_;
-    target->pixelSpacingX_ = pixelSpacingX_;
-    target->pixelSpacingY_ = pixelSpacingY_;
-    target->thickness_ = thickness_;
-    target->width_ = width_;
-    target->height_ = height_;
-    target->converter_ = converter_;
-    if (imageInformation_.get() != NULL)
-      target->imageInformation_.reset(imageInformation_->Clone());
-
-    return target.release();
-  }
-  
-  bool Slice::ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset,
-                                    unsigned int frame)
-  {
-    // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html
-
-    {
-      std::string increment;
-
-      if (dataset.CopyToString(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false))
-      {
-        Orthanc::Toolbox::ToUpperCase(increment);
-        if (increment != "3004,000C")  // This is the "Grid Frame Offset Vector" tag
-        {
-          LOG(ERROR) << "Bad value for the \"FrameIncrementPointer\" tag";
-          return false;
-        }
-      }
-    }
-
-    std::string offsetTag;
-
-    if (!dataset.CopyToString(offsetTag, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, false) ||
-        offsetTag.empty())
-    {
-      LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1";
-      return false;
-    }
-
-    std::vector<std::string> offsets;
-    Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\');
-
-    if (frameCount_ <= 1 ||
-        offsets.size() < frameCount_ ||
-        offsets.size() < 2 ||
-        frame >= frameCount_)
-    {
-      LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE";
-      return false;
-    }
-
-    double offset0, offset1, z;
-
-    if (!ParseDouble(offset0, offsets[0]) ||
-        !ParseDouble(offset1, offsets[1]) ||
-        !ParseDouble(z, offsets[frame]))
-    {
-      LOG(ERROR) << "Invalid syntax";
-      return false;
-    }
-
-    if (!OrthancStone::LinearAlgebra::IsCloseToZero(offset0))
-    {
-      LOG(ERROR) << "Invalid syntax";
-      return false;
-    }
-
-    geometry_ = OrthancStone::CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(),
-                                                 //+ 650 * geometry_.GetAxisX(),
-                                                 geometry_.GetAxisX(),
-                                                 geometry_.GetAxisY());
-
-    thickness_ = offset1 - offset0;
-    if (thickness_ < 0)
-    {
-      thickness_ = -thickness_;
-    }
-
-    return true;
-  }
-
-  
-  bool Slice::ParseOrthancFrame(const Orthanc::DicomMap& dataset,
-                                const std::string& instanceId,
-                                unsigned int frame)
-  {
-    orthancInstanceId_ = instanceId;
-    frame_ = frame;
-    type_ = Type_OrthancDecodableFrame;
-    imageInformation_.reset(new Orthanc::DicomImageInformation(dataset));
-
-    if (!dataset.CopyToString(sopClassUid_, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) ||
-        sopClassUid_.empty())
-    {
-      LOG(ERROR) << "Instance without a SOP class UID";
-      return false; 
-    }
-
-    if (!dataset.ParseUnsignedInteger32(frameCount_, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES))
-    {
-      frameCount_ = 1;   // Assume instance with one frame
-    }
-
-    if (frame >= frameCount_)
-    {
-      return false;
-    }
-
-    if (!dataset.ParseUnsignedInteger32(width_, Orthanc::DICOM_TAG_COLUMNS) ||
-        !dataset.ParseUnsignedInteger32(height_, Orthanc::DICOM_TAG_ROWS))
-    {
-      return false;
-    }
-
-    thickness_ = 100.0 * std::numeric_limits<double>::epsilon();
-
-    std::string tmp;
-    if (dataset.CopyToString(tmp, Orthanc::DICOM_TAG_SLICE_THICKNESS, false))
-    {
-      if (!tmp.empty() &&
-          !ParseDouble(thickness_, tmp))
-      {
-        return false;  // Syntax error
-      }
-    }
-    
-    converter_.ReadParameters(dataset);
-
-    OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset);
-
-    std::string position, orientation;
-    if (dataset.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) &&
-        dataset.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false))
-    {
-      geometry_ = OrthancStone::CoordinateSystem3D(position, orientation);
-
-      bool ok = true;
-
-      switch (OrthancStone::StringToSopClassUid(sopClassUid_))
-      {
-        case OrthancStone::SopClassUid_RTDose:
-          type_ = Type_OrthancRawFrame;
-          ok = ComputeRTDoseGeometry(dataset, frame);
-          break;
-            
-        default:
-          break;
-      }
-
-      if (!ok)
-      {
-        LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame
-                   << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_;
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  
-  const std::string Slice::GetOrthancInstanceId() const
-  {
-    if (type_ == Type_OrthancDecodableFrame ||
-        type_ == Type_OrthancRawFrame)
-    {
-      return orthancInstanceId_;
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }   
-  }
-
-  
-  unsigned int Slice::GetFrame() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return frame_;
-  }
-
-  
-  const OrthancStone::CoordinateSystem3D& Slice::GetGeometry() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return geometry_;
-  }
-
-  
-  double Slice::GetThickness() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return thickness_;
-  }
-
-  
-  double Slice::GetPixelSpacingX() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return pixelSpacingX_;
-  }
-
-  
-  double Slice::GetPixelSpacingY() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return pixelSpacingY_;
-  }
-
-  
-  unsigned int Slice::GetWidth() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return width_;
-  }
-
-  
-  unsigned int Slice::GetHeight() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return height_;
-  }
-
-
-  const DicomFrameConverter& Slice::GetConverter() const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-        
-    return converter_;
-  }
-
-
-  bool Slice::ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
-  {
-    if (type_ == Type_Invalid)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-
-    bool opposite;
-    return (OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite,
-                                                                GetGeometry().GetNormal(),
-                                                                plane.GetNormal()) &&
-            OrthancStone::LinearAlgebra::IsNear(GetGeometry().ProjectAlongNormal(GetGeometry().GetOrigin()),
-                                                GetGeometry().ProjectAlongNormal(plane.GetOrigin()),
-                                                thickness_ / 2.0));
-  }
-
-  
-  void Slice::GetExtent(std::vector<OrthancStone::Vector>& points) const
-  {
-    double sx = GetPixelSpacingX();
-    double sy = GetPixelSpacingY();
-    double w = static_cast<double>(GetWidth());
-    double h = static_cast<double>(GetHeight());
-
-    points.clear();
-    points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5      * sx, -0.5      * sy));
-    points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, -0.5      * sy));
-    points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5      * sx, (h - 0.5) * sy));
-    points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, (h - 0.5) * sy));
-  }
-
-
-  const Orthanc::DicomImageInformation& Slice::GetImageInformation() const
-  {
-    if (imageInformation_.get() == NULL)
-    {
-      // Only available if constructing the "Slice" object with a DICOM map
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      return *imageInformation_;
-    }
-  }
-}
--- a/Framework/Toolbox/Slice.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CoordinateSystem3D.h"
-#include "DicomFrameConverter.h"
-
-#include <Core/DicomFormat/DicomImageInformation.h>
-#include <Core/IDynamicObject.h>
-
-namespace Deprecated
-{
-  // TODO - Remove this class
-  class Slice :
-    public Orthanc::IDynamicObject  /* to be used as a payload of SlicesSorter */
-  {
-  private:
-    enum Type
-    {
-      Type_Invalid,
-      Type_Standalone,
-      Type_OrthancDecodableFrame,
-      Type_OrthancRawFrame
-      // TODO A slice could come from some DICOM file (URL)
-    };
-
-    bool ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset,
-                               unsigned int frame);
-
-    Type                 type_;
-    std::string          orthancInstanceId_;
-    std::string          sopClassUid_;
-    unsigned int         frame_;
-    unsigned int         frameCount_;   // TODO : Redundant with "imageInformation_"
-    OrthancStone::CoordinateSystem3D   geometry_;
-    double               pixelSpacingX_;
-    double               pixelSpacingY_;
-    double               thickness_;
-    unsigned int         width_;   // TODO : Redundant with "imageInformation_"
-    unsigned int         height_;   // TODO : Redundant with "imageInformation_"
-    DicomFrameConverter  converter_;   // TODO : Partially redundant with "imageInformation_"
-
-    std::auto_ptr<Orthanc::DicomImageInformation>  imageInformation_;
-
-  public:
-    Slice() :
-      type_(Type_Invalid)
-    {
-    }
-
-
-    // this constructor is used to reference, i.e, a slice that is being loaded
-    Slice(const std::string& orthancInstanceId,
-          unsigned int frame) :
-      type_(Type_Invalid),
-      orthancInstanceId_(orthancInstanceId),
-      frame_(frame)
-    {        
-    }
-
-    // TODO Is this constructor the best way to go to tackle missing
-    // layers within SliceViewerWidget?
-    Slice(const OrthancStone::CoordinateSystem3D& plane,
-          double thickness) :
-      type_(Type_Standalone),
-      frame_(0),
-      frameCount_(0),
-      geometry_(plane),
-      pixelSpacingX_(1),
-      pixelSpacingY_(1),
-      thickness_(thickness),
-      width_(0),
-      height_(0)
-    {      
-    }
-
-    Slice(const OrthancStone::CoordinateSystem3D& plane,
-          double pixelSpacingX,
-          double pixelSpacingY,
-          double thickness,
-          unsigned int width,
-          unsigned int height,
-          const DicomFrameConverter& converter) :
-      type_(Type_Standalone),
-      frameCount_(1),
-      geometry_(plane),
-      pixelSpacingX_(pixelSpacingX),
-      pixelSpacingY_(pixelSpacingY),
-      thickness_(thickness),
-      width_(width),
-      height_(height),
-      converter_(converter)
-    {
-    }
-
-    bool IsValid() const
-    {
-      return type_ != Type_Invalid;
-    } 
-
-    bool ParseOrthancFrame(const Orthanc::DicomMap& dataset,
-                           const std::string& instanceId,
-                           unsigned int frame);
-
-    bool HasOrthancDecoding() const
-    {
-      return type_ == Type_OrthancDecodableFrame;
-    }
-
-    const std::string GetOrthancInstanceId() const;
-
-    unsigned int GetFrame() const;
-
-    const OrthancStone::CoordinateSystem3D& GetGeometry() const;
-
-    double GetThickness() const;
-
-    double GetPixelSpacingX() const;
-
-    double GetPixelSpacingY() const;
-
-    unsigned int GetWidth() const;
-
-    unsigned int GetHeight() const;
-
-    const DicomFrameConverter& GetConverter() const;
-
-    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const;
-
-    void GetExtent(std::vector<OrthancStone::Vector>& points) const;
-
-    const Orthanc::DicomImageInformation& GetImageInformation() const;
-
-    Slice* Clone() const;
-  };
-}
--- a/Framework/Toolbox/ViewportGeometry.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ViewportGeometry.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/math/special_functions/round.hpp>
-
-namespace Deprecated
-{
-  void ViewportGeometry::ComputeTransform()
-  {
-    // The following lines must be read in reverse order!
-    cairo_matrix_t tmp;
-    
-    // Bring the center of the scene to the center of the view
-    cairo_matrix_init_translate(&transform_, 
-                                panX_ + static_cast<double>(width_) / 2.0, 
-                                panY_ + static_cast<double>(height_) / 2.0);
-
-    // Apply the zoom around (0,0)
-    cairo_matrix_init_scale(&tmp, zoom_, zoom_);
-    cairo_matrix_multiply(&transform_, &tmp, &transform_);
-
-    // Bring the center of the scene to (0,0)
-    cairo_matrix_init_translate(&tmp,
-                                -(sceneExtent_.GetX1() + sceneExtent_.GetX2()) / 2.0,
-                                -(sceneExtent_.GetY1() + sceneExtent_.GetY2()) / 2.0);
-    cairo_matrix_multiply(&transform_, &tmp, &transform_);
-  }
-
-
-  ViewportGeometry::ViewportGeometry()
-  {
-    width_ = 0;
-    height_ = 0;
-
-    zoom_ = 1;
-    panX_ = 0;
-    panY_ = 0;
-
-    ComputeTransform();
-  }
-
-
-  void ViewportGeometry::SetDisplaySize(unsigned int width,
-                                        unsigned int height)
-  {
-    if (width_ != width ||
-        height_ != height)
-    {
-      LOG(INFO) << "New display size: " << width << "x" << height;
-
-      width_ = width;
-      height_ = height;
-
-      ComputeTransform();
-    }
-  }
-
-
-  void ViewportGeometry::SetSceneExtent(const OrthancStone::Extent2D& extent)
-  {
-    LOG(INFO) << "New scene extent: ("
-              << extent.GetX1() << "," << extent.GetY1() << ") => ("
-              << extent.GetX2() << "," << extent.GetY2() << ")";
-
-    sceneExtent_ = extent;
-    ComputeTransform();
-  }
-
-
-  void ViewportGeometry::MapDisplayToScene(double& sceneX /* out */,
-                                           double& sceneY /* out */,
-                                           double x,
-                                           double y) const
-  {
-    cairo_matrix_t transform = transform_;
-
-    if (cairo_matrix_invert(&transform) != CAIRO_STATUS_SUCCESS)
-    {
-      LOG(ERROR) << "Cannot invert singular matrix";
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-
-    sceneX = x;
-    sceneY = y;
-    cairo_matrix_transform_point(&transform, &sceneX, &sceneY);
-  }
-
-
-  void ViewportGeometry::MapSceneToDisplay(int& displayX /* out */,
-                                           int& displayY /* out */,
-                                           double x,
-                                           double y) const
-  {
-    cairo_matrix_transform_point(&transform_, &x, &y);
-
-    displayX = static_cast<int>(boost::math::iround(x));
-    displayY = static_cast<int>(boost::math::iround(y));
-  }
-
-
-  void ViewportGeometry::MapPixelCenterToScene(std::vector<Touch>& sceneTouches /* out */,
-                                               const std::vector<Touch>& displayTouches) const
-  {
-    double sceneX, sceneY;
-    sceneTouches.clear();
-    for (size_t t = 0; t < displayTouches.size(); t++)
-    {
-      MapPixelCenterToScene(
-        sceneX,
-        sceneY, 
-        static_cast<int>(displayTouches[t].x), 
-        static_cast<int>(displayTouches[t].y));
-      
-      sceneTouches.push_back(Touch((float)sceneX, (float)sceneY));
-    }
-  }
-
-  void ViewportGeometry::MapPixelCenterToScene(double& sceneX,
-                                               double& sceneY,
-                                               int x,
-                                               int y) const
-  {
-    // Take the center of the pixel
-    MapDisplayToScene(sceneX, sceneY,
-                      static_cast<double>(x) + 0.5,
-                      static_cast<double>(y) + 0.5);
-  }
-
-
-  void ViewportGeometry::FitContent()
-  {
-    if (width_ > 0 &&
-        height_ > 0 &&
-        !sceneExtent_.IsEmpty())
-    {
-      double zoomX = static_cast<double>(width_) / (sceneExtent_.GetX2() - sceneExtent_.GetX1());
-      double zoomY = static_cast<double>(height_) / (sceneExtent_.GetY2() - sceneExtent_.GetY1());
-      zoom_ = zoomX < zoomY ? zoomX : zoomY;
-
-      panX_ = 0;
-      panY_ = 0;
-
-      ComputeTransform();
-    }
-  }
-
-
-  void ViewportGeometry::ApplyTransform(OrthancStone::CairoContext& context) const
-  {
-    cairo_set_matrix(context.GetObject(), &transform_);
-  }
-
-
-  void ViewportGeometry::GetPan(double& x,
-                                double& y) const
-  {
-    x = panX_;
-    y = panY_;
-  }
-
-
-  void ViewportGeometry::SetPan(double x,
-                                double y)
-  {
-    panX_ = x;
-    panY_ = y;
-    ComputeTransform();
-  }
-
-
-  void ViewportGeometry::SetZoom(double zoom)
-  {
-    zoom_ = zoom;
-    ComputeTransform();
-  }
-
-
-  OrthancStone::Matrix ViewportGeometry::GetMatrix() const
-  {
-    OrthancStone::Matrix m(3, 3);
-
-    m(0, 0) = transform_.xx;
-    m(0, 1) = transform_.xy;
-    m(0, 2) = transform_.x0;
-    m(1, 0) = transform_.yx;
-    m(1, 1) = transform_.yy;
-    m(1, 2) = transform_.y0;
-    m(2, 0) = 0;
-    m(2, 1) = 0;
-    m(2, 2) = 1;
-    
-    return m;
-  }
-}
--- a/Framework/Toolbox/ViewportGeometry.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "../Viewport/CairoContext.h"
-#include "Extent2D.h"
-#include "LinearAlgebra.h"
-#include "../Viewport/IMouseTracker.h"  // to include "Touch" definition
-
-namespace Deprecated
-{
-  class ViewportGeometry
-  {
-  private:
-    // Extent of the scene (in world units)
-    OrthancStone::Extent2D   sceneExtent_;
-
-    // Size of the display (in pixels)
-    unsigned int  width_;
-    unsigned int  height_;
-
-    // Zoom/pan
-    double   zoom_;
-    double   panX_;  // In pixels (display units)
-    double   panY_;
-
-    cairo_matrix_t  transform_;  // Scene-to-display transformation
-
-    void ComputeTransform();
-
-  public:
-    ViewportGeometry();
-
-    void SetDisplaySize(unsigned int width,
-                        unsigned int height);
-
-    void SetSceneExtent(const OrthancStone::Extent2D& extent);
-
-    const OrthancStone::Extent2D& GetSceneExtent() const
-    {
-      return sceneExtent_;
-    }
-
-    void MapDisplayToScene(double& sceneX /* out */,
-                           double& sceneY /* out */,
-                           double x,
-                           double y) const;
-
-    void MapPixelCenterToScene(double& sceneX /* out */,
-                               double& sceneY /* out */,
-                               int x,
-                               int y) const;
-
-    void MapPixelCenterToScene(std::vector<Touch>& sceneTouches /* out */,
-                               const std::vector<Touch>& displayTouches) const;
-
-    void MapSceneToDisplay(int& displayX /* out */,
-                           int& displayY /* out */,
-                           double x,
-                           double y) const;
-
-    unsigned int GetDisplayWidth() const
-    {
-      return width_;
-    }
-
-    unsigned int GetDisplayHeight() const
-    {
-      return height_;
-    }
-
-    double GetZoom() const
-    {
-      return zoom_;
-    }
-
-    void FitContent();
-
-    void ApplyTransform(OrthancStone::CairoContext& context) const;
-
-    void GetPan(double& x,
-                double& y) const;
-
-    void SetPan(double x,
-                double y);
-
-    void SetZoom(double zoom);
-
-    OrthancStone::Matrix GetMatrix() const;
-  };
-}
--- a/Framework/Viewport/IMouseTracker.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CairoSurface.h"
-#include <vector>
-
-namespace Deprecated
-{
-  struct Touch
-  {
-    float x;
-    float y;
-
-    Touch(float x, float y)
-    : x(x),
-      y(y)
-    {
-    }
-    Touch()
-      : x(0.0f),
-        y(0.0f)
-    {
-    }
-  };
-
-
-  // this is tracking a mouse in screen coordinates/pixels unlike
-  // the IWorldSceneMouseTracker that is tracking a mouse
-  // in scene coordinates/mm.
-  class IMouseTracker : public boost::noncopyable
-  {
-  public:
-    virtual ~IMouseTracker()
-    {
-    }
-    
-    virtual void Render(Orthanc::ImageAccessor& surface) = 0;
-
-    virtual void MouseUp() = 0;
-
-    // Returns "true" iff. the background scene must be repainted
-    virtual void MouseMove(int x, 
-                           int y,
-                           const std::vector<Touch>& displayTouches) = 0;
-  };
-}
--- a/Framework/Viewport/IStatusBar.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 <boost/noncopyable.hpp>
-
-namespace Deprecated
-{
-  class IStatusBar : public boost::noncopyable
-  {
-  public:
-    virtual ~IStatusBar()
-    {
-    }
-    
-    virtual void ClearMessage() = 0;
-
-    virtual void SetMessage(const std::string& message) = 0;
-  };
-}
--- a/Framework/Viewport/IViewport.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IStatusBar.h"
-#include "../StoneEnumerations.h"
-#include "../Messages/IObservable.h"
-
-#include <Core/Images/ImageAccessor.h>
-#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition
-
-namespace Deprecated
-{
-  class IWidget;   // Forward declaration
-  
-  class IViewport : public OrthancStone::IObservable
-  {
-  public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport);
-
-    IViewport(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
-    virtual ~IViewport()
-    {
-    }
-
-    virtual void FitContent() = 0;
-
-    virtual void SetStatusBar(IStatusBar& statusBar) = 0;
-
-    virtual void SetSize(unsigned int width,
-                         unsigned int height) = 0;
-
-    // The function returns "true" iff. a new frame was rendered
-    virtual bool Render(Orthanc::ImageAccessor& surface) = 0;
-
-    virtual void MouseDown(OrthancStone::MouseButton button,
-                           int x,
-                           int y,
-                           OrthancStone::KeyboardModifiers modifiers,
-                           const std::vector<Touch>& touches) = 0;
-
-    virtual void MouseUp() = 0;
-
-    virtual void MouseMove(int x, 
-                           int y,
-                           const std::vector<Touch>& displayTouches) = 0;
-
-    virtual void MouseEnter() = 0;
-
-    virtual void MouseLeave() = 0;
-
-    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                            int x,
-                            int y,
-                            OrthancStone::KeyboardModifiers modifiers) = 0;
-
-    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers) = 0;
-
-    virtual bool HasAnimation() = 0;
-
-    virtual void DoAnimation() = 0;
-
-    // Should only be called from IWidget
-    // TODO Why should this be virtual?
-    virtual void NotifyContentChanged()
-    {
-      BroadcastMessage(ViewportChangedMessage(*this));
-    }
-  };
-}
--- a/Framework/Viewport/WidgetViewport.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WidgetViewport.h"
-
-#include <Core/Images/ImageProcessing.h>
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) :
-    IViewport(broker),
-    statusBar_(NULL),
-    isMouseOver_(false),
-    lastMouseX_(0),
-    lastMouseY_(0),
-    backgroundChanged_(false)
-  {
-  }
-
-
-  void WidgetViewport::FitContent()
-  {
-    if (centralWidget_.get() != NULL)
-    {
-      centralWidget_->FitContent();
-    }
-  }
-
-
-  void WidgetViewport::SetStatusBar(IStatusBar& statusBar)
-  {
-    statusBar_ = &statusBar;
-
-    if (centralWidget_.get() != NULL)
-    {
-      centralWidget_->SetStatusBar(statusBar);
-    }
-  }
-
-
-  IWidget& WidgetViewport::SetCentralWidget(IWidget* widget)
-  {
-    if (widget == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    mouseTracker_.reset(NULL);
-
-    centralWidget_.reset(widget);
-    centralWidget_->SetViewport(*this);
-
-    if (statusBar_ != NULL)
-    {
-      centralWidget_->SetStatusBar(*statusBar_);
-    }
-
-    NotifyBackgroundChanged();
-
-    return *widget;
-  }
-
-
-  void WidgetViewport::NotifyBackgroundChanged()
-  {
-    backgroundChanged_ = true;
-    NotifyContentChanged();
-  }
-
-
-  void WidgetViewport::SetSize(unsigned int width,
-                               unsigned int height)
-  {
-    background_.SetSize(width, height, false /* no alpha */);
-
-    if (centralWidget_.get() != NULL)
-    {
-      centralWidget_->SetSize(width, height);
-    }
-
-    NotifyBackgroundChanged();
-  }
-
-
-  bool WidgetViewport::Render(Orthanc::ImageAccessor& surface)
-  {
-    if (centralWidget_.get() == NULL)
-    {
-      return false;
-    }
-
-    Orthanc::ImageAccessor background;
-    background_.GetWriteableAccessor(background);
-
-    if (backgroundChanged_ &&
-        !centralWidget_->Render(background))
-    {
-      return false;
-    }
-
-    if (background.GetWidth() != surface.GetWidth() ||
-        background.GetHeight() != surface.GetHeight())
-    {
-      return false;
-    }
-
-    Orthanc::ImageProcessing::Convert(surface, background);
-    
-    if (mouseTracker_.get() != NULL)
-    {
-      mouseTracker_->Render(surface);
-    }
-    else if (isMouseOver_)
-    {
-      centralWidget_->RenderMouseOver(surface, lastMouseX_, lastMouseY_);
-    }
-
-    return true;
-  }
-
-  void WidgetViewport::TouchStart(const std::vector<Touch>& displayTouches)
-  {
-    MouseDown(OrthancStone::MouseButton_Left, (int)displayTouches[0].x, (int)displayTouches[0].y, OrthancStone::KeyboardModifiers_None, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates
-  }
-      
-  void WidgetViewport::TouchMove(const std::vector<Touch>& displayTouches)
-  {
-    MouseMove((int)displayTouches[0].x, (int)displayTouches[0].y, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates
-  }
-      
-  void WidgetViewport::TouchEnd(const std::vector<Touch>& displayTouches)
-  {
-    // note: TouchEnd is not triggered when a single touch gesture ends (it is only triggered when
-    // going from 2 touches to 1 touch, ...)
-    MouseUp();
-  }
-
-  void WidgetViewport::MouseDown(OrthancStone::MouseButton button,
-                                 int x,
-                                 int y,
-                                 OrthancStone::KeyboardModifiers modifiers,
-                                 const std::vector<Touch>& displayTouches
-                                 )
-  {
-    lastMouseX_ = x;
-    lastMouseY_ = y;
-
-    if (centralWidget_.get() != NULL)
-    {
-      mouseTracker_.reset(centralWidget_->CreateMouseTracker(button, x, y, modifiers, displayTouches));
-    }
-    else
-    {
-      mouseTracker_.reset(NULL);
-    }      
-
-    NotifyContentChanged();
-  }
-
-
-  void WidgetViewport::MouseUp()
-  {
-    if (mouseTracker_.get() != NULL)
-    {
-      mouseTracker_->MouseUp();
-      mouseTracker_.reset(NULL);
-      NotifyContentChanged();
-    }
-  }
-
-
-  void WidgetViewport::MouseMove(int x, 
-                                 int y,
-                                 const std::vector<Touch>& displayTouches)
-  {
-    if (centralWidget_.get() == NULL)
-    {
-      return;
-    }
-
-    lastMouseX_ = x;
-    lastMouseY_ = y;
-
-    bool repaint = false;
-    
-    if (mouseTracker_.get() != NULL)
-    {
-      mouseTracker_->MouseMove(x, y, displayTouches);
-      repaint = true;
-    }
-    else
-    {
-      repaint = centralWidget_->HasRenderMouseOver();
-    }
-
-    if (repaint)
-    {
-      // The scene must be repainted, notify the observers
-      NotifyContentChanged();
-    }
-  }
-
-
-  void WidgetViewport::MouseEnter()
-  {
-    isMouseOver_ = true;
-    NotifyContentChanged();
-  }
-
-
-  void WidgetViewport::MouseLeave()
-  {
-    isMouseOver_ = false;
-
-    if (mouseTracker_.get() != NULL)
-    {
-      mouseTracker_->MouseUp();
-      mouseTracker_.reset(NULL);
-    }
-
-    NotifyContentChanged();
-  }
-
-
-  void WidgetViewport::MouseWheel(OrthancStone::MouseWheelDirection direction,
-                                  int x,
-                                  int y,
-                                  OrthancStone::KeyboardModifiers modifiers)
-  {
-    if (centralWidget_.get() != NULL &&
-        mouseTracker_.get() == NULL)
-    {
-      centralWidget_->MouseWheel(direction, x, y, modifiers);
-    }
-  }
-
-
-  void WidgetViewport::KeyPressed(OrthancStone::KeyboardKeys key,
-                                  char keyChar,
-                                  OrthancStone::KeyboardModifiers modifiers)
-  {
-    if (centralWidget_.get() != NULL &&
-        mouseTracker_.get() == NULL)
-    {
-      centralWidget_->KeyPressed(key, keyChar, modifiers);
-    }
-  }
-
-
-  bool WidgetViewport::HasAnimation()
-  {
-    if (centralWidget_.get() != NULL)
-    {
-      return centralWidget_->HasAnimation();
-    }
-    else
-    {
-      return false;
-    }
-  }
-   
-
-  void WidgetViewport::DoAnimation()
-  {
-    if (centralWidget_.get() != NULL)
-    {
-      centralWidget_->DoAnimation();
-    }
-  }
-}
--- a/Framework/Viewport/WidgetViewport.h	Tue May 21 13:27:54 2019 +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-2019 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 "IViewport.h"
-#include "../Widgets/IWidget.h"
-
-#include <memory>
-
-namespace Deprecated
-{
-  class WidgetViewport : public IViewport
-  {
-  private:
-    std::auto_ptr<IWidget>        centralWidget_;
-    IStatusBar*                   statusBar_;
-    std::auto_ptr<IMouseTracker>  mouseTracker_;
-    bool                          isMouseOver_;
-    int                           lastMouseX_;
-    int                           lastMouseY_;
-    OrthancStone::CairoSurface    background_;
-    bool                          backgroundChanged_;
-
-  public:
-    WidgetViewport(OrthancStone::MessageBroker& broker);
-
-    virtual void FitContent();
-
-    virtual void SetStatusBar(IStatusBar& statusBar);
-
-    IWidget& SetCentralWidget(IWidget* widget);  // Takes ownership
-
-    virtual void NotifyBackgroundChanged();
-
-    virtual void SetSize(unsigned int width,
-                         unsigned int height);
-
-    virtual bool Render(Orthanc::ImageAccessor& surface);
-
-    virtual void MouseDown(OrthancStone::MouseButton button,
-                           int x,
-                           int y,
-                           OrthancStone::KeyboardModifiers modifiers,
-                           const std::vector<Touch>& displayTouches);
-
-    virtual void MouseUp();
-
-    virtual void MouseMove(int x, 
-                           int y,
-                           const std::vector<Touch>& displayTouches);
-
-    virtual void MouseEnter();
-
-    virtual void MouseLeave();
-
-    virtual void TouchStart(const std::vector<Touch>& touches);
-    
-    virtual void TouchMove(const std::vector<Touch>& touches);
-    
-    virtual void TouchEnd(const std::vector<Touch>& touches);
-
-    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                            int x,
-                            int y,
-                            OrthancStone::KeyboardModifiers modifiers);
-
-    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers);
-
-    virtual bool HasAnimation();
-
-    virtual void DoAnimation();
-  };
-}
--- a/Framework/Volumes/ISlicedVolume.h	Tue May 21 13:27:54 2019 +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-2019 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 "../Messages/IObservable.h"
-#include "../Toolbox/Slice.h"
-
-namespace Deprecated
-{
-  class ISlicedVolume : public OrthancStone::IObservable
-  {
-  public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, ISlicedVolume);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, ISlicedVolume);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, ISlicedVolume);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeReadyMessage, ISlicedVolume);
-
-
-    class SliceContentChangedMessage : public OrthancStone::OriginMessage<ISlicedVolume>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      size_t        sliceIndex_;
-      const Slice&  slice_;
-      
-    public:
-      SliceContentChangedMessage(ISlicedVolume& origin,
-                                 size_t sliceIndex,
-                                 const Slice& slice) :
-        OriginMessage(origin),
-        sliceIndex_(sliceIndex),
-        slice_(slice)
-      {
-      }
-
-      size_t GetSliceIndex() const
-      {
-        return sliceIndex_;
-      }
-
-      const Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-
-    ISlicedVolume(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
-    virtual size_t GetSliceCount() const = 0;
-
-    virtual const Slice& GetSlice(size_t slice) const = 0;
-  };
-}
--- a/Framework/Volumes/IVolumeLoader.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "../Messages/IObservable.h"
-
-namespace Deprecated
-{
-  class IVolumeLoader : public OrthancStone::IObservable
-  {
-  public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader);
-
-    IVolumeLoader(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-  };
-}
--- a/Framework/Volumes/ImageBuffer3D.h	Tue May 21 13:27:54 2019 +0200
+++ b/Framework/Volumes/ImageBuffer3D.h	Tue May 21 14:27:35 2019 +0200
@@ -21,11 +21,11 @@
 
 #pragma once
 
+#include "../Deprecated/Layers/RenderStyle.h"
+#include "../Deprecated/Toolbox/DicomFrameConverter.h"
 #include "../StoneEnumerations.h"
-#include "../Layers/RenderStyle.h"
+#include "../Toolbox/ParallelSlices.h"
 #include "../Toolbox/VolumeImageGeometry.h"
-#include "../Toolbox/DicomFrameConverter.h"
-#include "../Toolbox/ParallelSlices.h"
 
 #include <Core/Images/Image.h>
 
--- a/Framework/Volumes/StructureSetLoader.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "StructureSetLoader.h"
-
-#include "../Toolbox/MessagingToolbox.h"
-
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker,
-                                         OrthancApiClient& orthanc) :
-    IVolumeLoader(broker),
-    IObserver(broker),
-    orthanc_(orthanc)
-  {
-  }
-  
-
-  void StructureSetLoader::OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
-
-    Orthanc::DicomMap slice;
-    OrthancStone::MessagingToolbox::ConvertDataset(slice, dataset);
-    structureSet_->AddReferencedSlice(slice);
-
-    BroadcastMessage(ContentChangedMessage(*this));
-  }
-  
-
-  void StructureSetLoader::OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
-    structureSet_.reset(new OrthancStone::DicomStructureSet(dataset));
-
-    std::set<std::string> instances;
-    structureSet_->GetReferencedInstances(instances);
-
-    for (std::set<std::string>::const_iterator it = instances.begin();
-         it != instances.end(); ++it)
-    {
-      orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it,
-                                         new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted));
-    }
-
-    BroadcastMessage(GeometryReadyMessage(*this));
-  }
-
-  
-  void StructureSetLoader::OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message)
-  {
-    const Json::Value& lookup = message.GetJson();
-
-    if (lookup.type() != Json::arrayValue ||
-        lookup.size() != 1 ||
-        !lookup[0].isMember("Type") ||
-        !lookup[0].isMember("Path") ||
-        lookup[0]["Type"].type() != Json::stringValue ||
-        lookup[0]["ID"].type() != Json::stringValue ||
-        lookup[0]["Type"].asString() != "Instance")
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
-    }
-
-    const std::string& instance = lookup[0]["ID"].asString();
-    orthanc_.GetJsonAsync("/instances/" + instance + "/tags",
-                          new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnReferencedSliceLoaded));
-  }
-
-  
-  void StructureSetLoader::ScheduleLoadInstance(const std::string& instance)
-  {
-    if (structureSet_.get() != NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050",
-                            new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnStructureSetLoaded));
-    }
-  }
-
-
-  OrthancStone::DicomStructureSet& StructureSetLoader::GetStructureSet()
-  {
-    if (structureSet_.get() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      return *structureSet_;
-    }
-  }
-}
--- a/Framework/Volumes/StructureSetLoader.h	Tue May 21 13:27:54 2019 +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-2019 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 "../Toolbox/DicomStructureSet.h"
-#include "../Toolbox/OrthancApiClient.h"
-#include "IVolumeLoader.h"
-
-namespace Deprecated
-{
-  class StructureSetLoader :
-    public IVolumeLoader,
-    public OrthancStone::IObserver
-  {
-  private:
-    OrthancApiClient&                 orthanc_;
-    std::auto_ptr<OrthancStone::DicomStructureSet>  structureSet_;
-
-    void OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-    void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message);
-
-  public:
-    StructureSetLoader(OrthancStone::MessageBroker& broker,
-                       OrthancApiClient& orthanc);
-
-    void ScheduleLoadInstance(const std::string& instance);
-
-    bool HasStructureSet() const
-    {
-      return structureSet_.get() != NULL;
-    }
-
-    OrthancStone::DicomStructureSet& GetStructureSet();
-  };
-}
--- a/Framework/Widgets/CairoWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CairoWidget.h"
-
-#include <Core/Images/ImageProcessing.h>
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  static bool IsAligned(const Orthanc::ImageAccessor& target)
-  {
-    // TODO
-    return true;
-  }
-
-  CairoWidget::CairoWidget(const std::string& name) :
-    WidgetBase(name)
-  {
-  }
-
-  void CairoWidget::SetSize(unsigned int width,
-                            unsigned int height)
-  {
-    surface_.SetSize(width, height, false /* no alpha */);
-  }
-  
-
-  bool CairoWidget::Render(Orthanc::ImageAccessor& target)
-  {
-    // Don't call the base class here, as
-    // "ClearBackgroundCairo()" is a faster alternative
-
-    if (IsAligned(target))
-    {
-      OrthancStone::CairoSurface surface(target, false /* no alpha */);
-      OrthancStone::CairoContext context(surface);
-      ClearBackgroundCairo(context);
-      return RenderCairo(context);
-    }
-    else
-    {
-      OrthancStone::CairoContext context(surface_);
-      ClearBackgroundCairo(context);
-
-      if (RenderCairo(context))
-      {
-        Orthanc::ImageAccessor surface;
-        surface_.GetReadOnlyAccessor(surface);
-        Orthanc::ImageProcessing::Copy(target, surface);
-        return true;
-      }
-      else
-      {
-        return false;
-      }
-    }
-  }
-
-
-  void CairoWidget::RenderMouseOver(Orthanc::ImageAccessor& target,
-                                    int x,
-                                    int y)
-  {
-    if (IsAligned(target))
-    {
-      OrthancStone::CairoSurface surface(target, false /* no alpha */);
-      OrthancStone::CairoContext context(surface);
-      RenderMouseOverCairo(context, x, y);
-    }
-    else
-    {
-      Orthanc::ImageAccessor accessor;
-      surface_.GetWriteableAccessor(accessor);
-      Orthanc::ImageProcessing::Copy(accessor, target);
-
-      OrthancStone::CairoContext context(surface_);
-      RenderMouseOverCairo(context, x, y);
-
-      Orthanc::ImageProcessing::Copy(target, accessor);
-    }
-  }
-}
--- a/Framework/Widgets/CairoWidget.h	Tue May 21 13:27:54 2019 +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-2019 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 "WidgetBase.h"
-
-namespace Deprecated
-{
-  class CairoWidget : public WidgetBase
-  {
-  private:
-    OrthancStone::CairoSurface   surface_;
-
-  protected:
-    virtual bool RenderCairo(OrthancStone::CairoContext& context) = 0;
-    
-    virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
-                                      int x,
-                                      int y) = 0;
-    
-  public:
-    CairoWidget(const std::string& name);
-
-    virtual void SetSize(unsigned int width,
-                         unsigned int height);
-
-    virtual bool Render(Orthanc::ImageAccessor& target);
-
-    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
-                                 int x,
-                                 int y);  
-  };
-}
--- a/Framework/Widgets/EmptyWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "EmptyWidget.h"
-
-#include <Core/Images/ImageProcessing.h>
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  bool EmptyWidget::Render(Orthanc::ImageAccessor& surface)
-  {
-    // Note: This call is slow
-    Orthanc::ImageProcessing::Set(surface, red_, green_, blue_, 255);
-    return true;
-  }
-
-
-  void EmptyWidget::DoAnimation()
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-  }
-}
--- a/Framework/Widgets/EmptyWidget.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IWidget.h"
-
-namespace Deprecated
-{
-  /**
-   * This is a test widget that simply fills its surface with an
-   * uniform color.
-   **/
-  class EmptyWidget : public IWidget
-  {
-  private:
-    uint8_t  red_;
-    uint8_t  green_;
-    uint8_t  blue_;
-
-  public:
-    EmptyWidget(uint8_t red,
-                uint8_t green,
-                uint8_t blue) :
-      red_(red),
-      green_(green),
-      blue_(blue)
-    {
-    }
-
-    virtual void FitContent()
-    {
-    }
-
-    virtual void SetParent(IWidget& widget)
-    {
-    }
-
-    virtual void SetViewport(WidgetViewport& viewport)
-    {
-    }
-
-    virtual void NotifyContentChanged()
-    {
-    }
-
-    virtual void SetStatusBar(IStatusBar& statusBar)
-    {
-    }
-
-    virtual void SetSize(unsigned int width,
-                         unsigned int height)
-    {
-    }
-
-    virtual bool Render(Orthanc::ImageAccessor& surface);
-
-    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
-                                              int x,
-                                              int y,
-                                              OrthancStone::KeyboardModifiers modifiers,
-                                              const std::vector<Touch>& touches)
-    {
-      return NULL;
-    }
-
-    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
-                                 int x,
-                                 int y)
-    {
-    }
-
-    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                            int x,
-                            int y,
-                            OrthancStone::KeyboardModifiers modifiers)
-    {
-    }
-
-    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers)
-    {
-    }
-
-    virtual bool HasAnimation() const
-    {
-      return false;
-    }
-
-    virtual void DoAnimation();
-
-    virtual bool HasRenderMouseOver()
-    {
-      return false;
-    }
-  };
-}
--- a/Framework/Widgets/IWidget.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "../StoneEnumerations.h"
-#include "../Viewport/IMouseTracker.h"
-#include "../Viewport/IStatusBar.h"
-
-namespace Deprecated
-{
-  class WidgetViewport;  // Forward declaration
-  
-  class IWidget : public boost::noncopyable
-  {
-  public:
-    virtual ~IWidget()
-    {
-    }
-
-    virtual void FitContent() = 0;
-
-    virtual void SetParent(IWidget& parent) = 0;
-    
-    virtual void SetViewport(WidgetViewport& viewport) = 0;
-
-    virtual void SetStatusBar(IStatusBar& statusBar) = 0;
-
-    virtual void SetSize(unsigned int width, 
-                         unsigned int height) = 0;
- 
-    virtual bool Render(Orthanc::ImageAccessor& surface) = 0;
-
-    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
-                                              int x,
-                                              int y,
-                                              OrthancStone::KeyboardModifiers modifiers,
-                                              const std::vector<Touch>& touches) = 0;
-
-    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
-                                 int x,
-                                 int y) = 0;
-
-    virtual bool HasRenderMouseOver() = 0;
-
-    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                            int x,
-                            int y,
-                            OrthancStone::KeyboardModifiers modifiers) = 0;
-
-    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers) = 0;
-
-    virtual bool HasAnimation() const = 0;
-
-    virtual void DoAnimation() = 0;
-
-    // Subclasses can call this method to signal the display of the
-    // widget must be refreshed
-    virtual void NotifyContentChanged() = 0;
-  };
-}
--- a/Framework/Widgets/IWorldSceneInteractor.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IWorldSceneMouseTracker.h"
-
-#include "../Toolbox/ViewportGeometry.h"
-#include "../StoneEnumerations.h"
-#include "../Viewport/IStatusBar.h"
-
-namespace Deprecated
-{
-    class WorldSceneWidget;
-
-    class IWorldSceneInteractor : public boost::noncopyable
-    {
-    public:
-        virtual ~IWorldSceneInteractor()
-        {
-        }
-
-        virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                            const ViewportGeometry& view,
-                                                            OrthancStone::MouseButton button,
-                                                            OrthancStone::KeyboardModifiers modifiers,
-                                                            int viewportX,
-                                                            int viewportY,
-                                                            double x,
-                                                            double y,
-                                                            IStatusBar* statusBar,
-                                                            const std::vector<Touch>& touches) = 0;
-
-        virtual void MouseOver(OrthancStone::CairoContext& context,
-                               WorldSceneWidget& widget,
-                               const ViewportGeometry& view,
-                               double x,
-                               double y,
-                               IStatusBar* statusBar) = 0;
-
-        virtual void MouseWheel(WorldSceneWidget& widget,
-                                OrthancStone::MouseWheelDirection direction,
-                                OrthancStone::KeyboardModifiers modifiers,
-                                IStatusBar* statusBar) = 0;
-
-        virtual void KeyPressed(WorldSceneWidget& widget,
-                                OrthancStone::KeyboardKeys key,
-                                char keyChar,
-                                OrthancStone::KeyboardModifiers modifiers,
-                                IStatusBar* statusBar) = 0;
-    };
-}
--- a/Framework/Widgets/IWorldSceneMouseTracker.h	Tue May 21 13:27:54 2019 +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-2019 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 "../Viewport/CairoContext.h"
-#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition
-
-namespace Deprecated
-{
-
-  // this is tracking a mouse in scene coordinates/mm unlike
-  // the IMouseTracker that is tracking a mouse
-  // in screen coordinates/pixels.
-  class IWorldSceneMouseTracker : public boost::noncopyable
-  {
-  public:
-    virtual ~IWorldSceneMouseTracker()
-    {
-    }
-
-    virtual bool HasRender() const = 0;
-
-    virtual void Render(OrthancStone::CairoContext& context,
-                        double zoom) = 0;
-
-    virtual void MouseUp() = 0;
-
-    virtual void MouseMove(int displayX,
-                           int displayY,
-                           double sceneX,
-                           double sceneY,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches) = 0;
-  };
-}
--- a/Framework/Widgets/LayoutWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,503 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "LayoutWidget.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/math/special_functions/round.hpp>
-
-namespace Deprecated
-{
-  class LayoutWidget::LayoutMouseTracker : public IMouseTracker
-  {
-  private:
-    std::auto_ptr<IMouseTracker>   tracker_;
-    int                            left_;
-    int                            top_;
-    unsigned int                   width_;
-    unsigned int                   height_;
-
-  public:
-    LayoutMouseTracker(IMouseTracker* tracker,
-                       int left,
-                       int top,
-                       unsigned int width,
-                       unsigned int height) :
-      tracker_(tracker),
-      left_(left),
-      top_(top),
-      width_(width),
-      height_(height)
-    {
-      if (tracker == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-    }
-
-    virtual void Render(Orthanc::ImageAccessor& surface)
-    {
-      Orthanc::ImageAccessor accessor;
-      surface.GetRegion(accessor, left_, top_, width_, height_);
-      tracker_->Render(accessor);
-    }
-
-    virtual void MouseUp()
-    {
-      tracker_->MouseUp();
-    }
-
-    virtual void MouseMove(int x, 
-                           int y,
-                           const std::vector<Touch>& displayTouches)
-    {
-      std::vector<Touch> relativeTouches;
-      for (size_t t = 0; t < displayTouches.size(); t++)
-      {
-        relativeTouches.push_back(Touch(displayTouches[t].x - left_, displayTouches[t].y - top_));
-      }
-
-      tracker_->MouseMove(x - left_, y - top_, relativeTouches);
-    }
-  };
-
-
-  class LayoutWidget::ChildWidget : public boost::noncopyable
-  {
-  private:
-    std::auto_ptr<IWidget>  widget_;
-    int                     left_;
-    int                     top_;
-    unsigned int            width_;
-    unsigned int            height_;
-
-  public:
-    ChildWidget(IWidget* widget) :
-      widget_(widget)
-    {
-      assert(widget != NULL);
-      SetEmpty();
-    }
-
-    void DoAnimation()
-    {
-      if (widget_->HasAnimation())
-      {
-        widget_->DoAnimation();
-      }
-    }
-
-    IWidget& GetWidget() const
-    {
-      return *widget_;
-    }
-
-    void SetRectangle(unsigned int left, 
-                      unsigned int top,
-                      unsigned int width,
-                      unsigned int height)
-    {
-      left_ = left;
-      top_ = top;
-      width_ = width;
-      height_ = height;
-
-      widget_->SetSize(width, height);
-    }
-
-    void SetEmpty()
-    {
-      SetRectangle(0, 0, 0, 0);
-    }
-
-    bool Contains(int x, 
-                  int y) const
-    {
-      return (x >= left_ && 
-              y >= top_ &&
-              x < left_ + static_cast<int>(width_) &&
-              y < top_ + static_cast<int>(height_));
-    }      
-
-    bool Render(Orthanc::ImageAccessor& target)
-    {
-      if (width_ == 0 ||
-          height_ == 0)
-      {
-        return true;
-      }
-      else 
-      {
-        Orthanc::ImageAccessor accessor;
-        target.GetRegion(accessor, left_, top_, width_, height_);
-        return widget_->Render(accessor);
-      }
-    }
-
-    IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
-                                      int x,
-                                      int y,
-                                      OrthancStone::KeyboardModifiers modifiers,
-                                      const std::vector<Touch>& touches)
-    {
-      if (Contains(x, y))
-      {
-        IMouseTracker* tracker = widget_->CreateMouseTracker(button, 
-                                                             x - left_, 
-                                                             y - top_, 
-                                                             modifiers,
-                                                             touches);
-        if (tracker)
-        {
-          return new LayoutMouseTracker(tracker, left_, top_, width_, height_);
-        }
-      }
-
-      return NULL;
-    }
-
-    void RenderMouseOver(Orthanc::ImageAccessor& target,
-                         int x,
-                         int y)
-    {
-      if (Contains(x, y))
-      {
-        Orthanc::ImageAccessor accessor;
-        target.GetRegion(accessor, left_, top_, width_, height_);
-
-        widget_->RenderMouseOver(accessor, x - left_, y - top_);
-      }
-    }
-
-    void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                    int x,
-                    int y,
-                    OrthancStone::KeyboardModifiers modifiers)
-    {
-      if (Contains(x, y))
-      {
-        widget_->MouseWheel(direction, x - left_, y - top_, modifiers);
-      }
-    }
-    
-    bool HasRenderMouseOver()
-    {
-      return widget_->HasRenderMouseOver();
-    }
-  };
-
-
-  void LayoutWidget::ComputeChildrenExtents()
-  {
-    if (children_.size() == 0)
-    {
-      return;
-    }
-
-    float internal = static_cast<float>(paddingInternal_);
-
-    if (width_ <= paddingLeft_ + paddingRight_ ||
-        height_ <= paddingTop_ + paddingBottom_)
-    {
-      for (size_t i = 0; i < children_.size(); i++)
-      {
-        children_[i]->SetEmpty();          
-      }
-    }
-    else if (isHorizontal_)
-    {
-      unsigned int padding = paddingLeft_ + paddingRight_ + (static_cast<unsigned int>(children_.size()) - 1) * paddingInternal_;
-      float childWidth = ((static_cast<float>(width_) - static_cast<float>(padding)) / 
-                          static_cast<float>(children_.size()));
-        
-      for (size_t i = 0; i < children_.size(); i++)
-      {
-        float left = static_cast<float>(paddingLeft_) + static_cast<float>(i) * (childWidth + internal);
-        float right = left + childWidth;
-
-        if (left >= right)
-        {
-          children_[i]->SetEmpty();
-        }
-        else
-        {
-          children_[i]->SetRectangle(static_cast<unsigned int>(left), 
-                                     paddingTop_, 
-                                     boost::math::iround(right - left),
-                                     height_ - paddingTop_ - paddingBottom_);
-        }
-      }
-    }
-    else
-    {
-      unsigned int padding = paddingTop_ + paddingBottom_ + (static_cast<unsigned int>(children_.size()) - 1) * paddingInternal_;
-      float childHeight = ((static_cast<float>(height_) - static_cast<float>(padding)) / 
-                           static_cast<float>(children_.size()));
-        
-      for (size_t i = 0; i < children_.size(); i++)
-      {
-        float top = static_cast<float>(paddingTop_) + static_cast<float>(i) * (childHeight + internal);
-        float bottom = top + childHeight;
-
-        if (top >= bottom)
-        {
-          children_[i]->SetEmpty();
-        }
-        else
-        {
-          children_[i]->SetRectangle(paddingTop_, 
-                                     static_cast<unsigned int>(top), 
-                                     width_ - paddingLeft_ - paddingRight_,
-                                     boost::math::iround(bottom - top));
-        }
-      }
-    }
-
-    NotifyContentChanged(*this);
-  }
-
-
-  LayoutWidget::LayoutWidget(const std::string& name) :
-    WidgetBase(name),
-    isHorizontal_(true),
-    width_(0),
-    height_(0),
-    paddingLeft_(0),
-    paddingTop_(0),
-    paddingRight_(0),
-    paddingBottom_(0),
-    paddingInternal_(0)
-  {
-  }
-
-
-  LayoutWidget::~LayoutWidget()
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      delete children_[i];
-    }
-  }
-
-
-  void LayoutWidget::FitContent()
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      children_[i]->GetWidget().FitContent();
-    }
-  }
-  
-
-  void LayoutWidget::NotifyContentChanged(const IWidget& widget)
-  {
-    // One of the children has changed
-    WidgetBase::NotifyContentChanged();
-  }
-
-
-  void LayoutWidget::SetHorizontal()
-  {
-    isHorizontal_ = true;
-    ComputeChildrenExtents();
-  }
-
-
-  void LayoutWidget::SetVertical()
-  {
-    isHorizontal_ = false;
-    ComputeChildrenExtents();
-  }
-
-
-  void LayoutWidget::SetPadding(unsigned int left,
-                                unsigned int top,
-                                unsigned int right,
-                                unsigned int bottom,
-                                unsigned int spacing)
-  {
-    paddingLeft_ = left;
-    paddingTop_ = top;
-    paddingRight_ = right;
-    paddingBottom_ = bottom;
-    paddingInternal_ = spacing;
-  }
-    
-
-  void LayoutWidget::SetPadding(unsigned int padding)
-  {
-    paddingLeft_ = padding;
-    paddingTop_ = padding;
-    paddingRight_ = padding;
-    paddingBottom_ = padding;
-    paddingInternal_ = padding;
-  }
-
-
-  IWidget& LayoutWidget::AddWidget(IWidget* widget)  // Takes ownership
-  {
-    if (widget == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    if (GetStatusBar() != NULL)
-    {
-      widget->SetStatusBar(*GetStatusBar());
-    }
-
-    children_.push_back(new ChildWidget(widget));
-    widget->SetParent(*this);
-
-    ComputeChildrenExtents();
-
-    if (widget->HasAnimation())
-    {
-      hasAnimation_ = true;
-    }
-
-    return *widget;
-  }
-
-
-  void LayoutWidget::SetStatusBar(IStatusBar& statusBar)
-  {
-    WidgetBase::SetStatusBar(statusBar);
-
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      children_[i]->GetWidget().SetStatusBar(statusBar);
-    }
-  }
-
-
-  void LayoutWidget::SetSize(unsigned int width,
-                             unsigned int height)
-  {
-    width_ = width;
-    height_ = height;
-    ComputeChildrenExtents();
-  }
-
-
-  bool LayoutWidget::Render(Orthanc::ImageAccessor& surface)
-  {
-    if (!WidgetBase::Render(surface))
-    {
-      return false;
-    }
-
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      if (!children_[i]->Render(surface))
-      {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-    
-  IMouseTracker* LayoutWidget::CreateMouseTracker(OrthancStone::MouseButton button,
-                                                  int x,
-                                                  int y,
-                                                  OrthancStone::KeyboardModifiers modifiers,
-                                                  const std::vector<Touch>& touches)
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      IMouseTracker* tracker = children_[i]->CreateMouseTracker(button, x, y, modifiers, touches);
-      if (tracker != NULL)
-      {
-        return tracker;
-      }
-    }
-
-    return NULL;
-  }
-
-
-  void LayoutWidget::RenderMouseOver(Orthanc::ImageAccessor& target,
-                                     int x,
-                                     int y)
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      children_[i]->RenderMouseOver(target, x, y);
-    }
-  }
-
-
-  void LayoutWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
-                                int x,
-                                int y,
-                                OrthancStone::KeyboardModifiers modifiers)
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      children_[i]->MouseWheel(direction, x, y, modifiers);
-    }
-  }
-
-
-  void LayoutWidget::KeyPressed(OrthancStone::KeyboardKeys key,
-                                char keyChar,
-                                OrthancStone::KeyboardModifiers modifiers)
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      children_[i]->GetWidget().KeyPressed(key, keyChar, modifiers);
-    }
-  }
-
-  
-  void LayoutWidget::DoAnimation()
-  {
-    if (hasAnimation_)
-    {
-      for (size_t i = 0; i < children_.size(); i++)
-      {
-        children_[i]->DoAnimation();
-      }
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-    }
-  }
-
-
-  bool LayoutWidget::HasRenderMouseOver()
-  {
-    for (size_t i = 0; i < children_.size(); i++)
-    {
-      if (children_[i]->HasRenderMouseOver())
-      {
-        return true;
-      }
-    }
-
-    return false;
-  }
-}
--- a/Framework/Widgets/LayoutWidget.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WidgetBase.h"
-
-#include <vector>
-#include <memory>
-
-namespace Deprecated
-{
-  class LayoutWidget : public WidgetBase
-  {
-  private:
-    class LayoutMouseTracker;
-    class ChildWidget;
-
-    std::vector<ChildWidget*>     children_;
-    bool                          isHorizontal_;
-    unsigned int                  width_;
-    unsigned int                  height_;
-    std::auto_ptr<IMouseTracker>  mouseTracker_;
-    unsigned int                  paddingLeft_;
-    unsigned int                  paddingTop_;
-    unsigned int                  paddingRight_;
-    unsigned int                  paddingBottom_;
-    unsigned int                  paddingInternal_;
-    bool                          hasAnimation_;
-
-    void ComputeChildrenExtents();
-
-  public:
-    LayoutWidget(const std::string& name);
-
-    virtual ~LayoutWidget();
-
-    virtual void FitContent();
-
-    virtual void NotifyContentChanged(const IWidget& widget);
-
-    void SetHorizontal();
-
-    void SetVertical();
-
-    void SetPadding(unsigned int left,
-                    unsigned int top,
-                    unsigned int right,
-                    unsigned int bottom,
-                    unsigned int spacing);
-    
-    void SetPadding(unsigned int padding);
-
-    unsigned int GetPaddingLeft() const
-    {
-      return paddingLeft_;
-    }
-
-    unsigned int GetPaddingTop() const
-    {
-      return paddingTop_;
-    }
-
-    unsigned int GetPaddingRight() const
-    {
-      return paddingRight_;
-    }
-
-    unsigned int GetPaddingBottom() const
-    {
-      return paddingBottom_;
-    }
-
-    unsigned int GetPaddingInternal() const
-    {
-      return paddingInternal_;
-    }
-
-    IWidget& AddWidget(IWidget* widget);  // Takes ownership
-
-    virtual void SetStatusBar(IStatusBar& statusBar);
-
-    virtual void SetSize(unsigned int width,
-                         unsigned int height);
-
-    virtual bool Render(Orthanc::ImageAccessor& surface);
-    
-    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
-                                              int x,
-                                              int y,
-                                              OrthancStone::KeyboardModifiers modifiers,
-                                              const std::vector<Touch>& touches);
-
-    virtual void RenderMouseOver(Orthanc::ImageAccessor& target,
-                                 int x,
-                                 int y);
-
-    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                            int x,
-                            int y,
-                            OrthancStone::KeyboardModifiers modifiers);
-
-    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers);
-
-    virtual bool HasAnimation() const
-    {
-      return hasAnimation_;
-    }
-
-    virtual void DoAnimation();
-
-    virtual bool HasRenderMouseOver();
-  };
-}
--- a/Framework/Widgets/PanMouseTracker.cpp	Tue May 21 13:27:54 2019 +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-2019 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 "PanMouseTracker.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  PanMouseTracker::PanMouseTracker(WorldSceneWidget& that,
-                                   int x,
-                                   int y) :
-    that_(that)
-  {
-    that.GetView().GetPan(originalPanX_, originalPanY_);
-    that.GetView().MapPixelCenterToScene(downX_, downY_, x, y);
-  }
-    
-
-  void PanMouseTracker::Render(OrthancStone::CairoContext& context,
-                               double zoom)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-  }
-
-
-  void PanMouseTracker::MouseMove(int displayX,
-                                  int displayY,
-                                  double x,
-                                  double y,
-                                  const std::vector<Touch>& displayTouches,
-                                  const std::vector<Touch>& sceneTouches)
-  {
-    ViewportGeometry view = that_.GetView();
-    view.SetPan(originalPanX_ + (x - downX_) * view.GetZoom(),
-                originalPanY_ + (y - downY_) * view.GetZoom());
-    that_.SetView(view);
-  }
-}
--- a/Framework/Widgets/PanMouseTracker.h	Tue May 21 13:27:54 2019 +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-2019 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 "WorldSceneWidget.h"
-
-namespace Deprecated
-{
-  class PanMouseTracker : public IWorldSceneMouseTracker
-  {
-  private:
-    WorldSceneWidget&  that_;
-    double             originalPanX_;
-    double             originalPanY_;
-    double             downX_;
-    double             downY_;
-    
-  public:
-    PanMouseTracker(WorldSceneWidget& that,
-                    int x,
-                    int y);
-    
-    virtual bool HasRender() const
-    {
-      return false;
-    }
-
-    virtual void MouseUp()
-    {
-    }
-
-    virtual void Render(OrthancStone::CairoContext& context,
-                        double zoom);
-
-    virtual void MouseMove(int displayX,
-                           int displayY,
-                           double x,
-                           double y,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
-  };
-}
--- a/Framework/Widgets/PanZoomMouseTracker.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "PanZoomMouseTracker.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-#include <math.h>
-
-namespace Deprecated
-{
-  Touch GetCenter(const std::vector<Touch>& touches)
-  {
-    return Touch((touches[0].x + touches[1].x) / 2.0f, (touches[0].y + touches[1].y) / 2.0f);
-  }
-
-  double GetDistance(const std::vector<Touch>& touches)
-  {
-    float dx = touches[0].x - touches[1].x;
-    float dy = touches[0].y - touches[1].y;
-    return sqrt((double)(dx * dx) + (double)(dy * dy));
-  }
-
-
-  PanZoomMouseTracker::PanZoomMouseTracker(WorldSceneWidget& that,
-                                           const std::vector<Touch>& startTouches)
-    : that_(that),
-      originalZoom_(that.GetView().GetZoom())
-  {
-    that.GetView().GetPan(originalPanX_, originalPanY_);
-    that.GetView().MapPixelCenterToScene(originalSceneTouches_, startTouches);
-
-    originalDisplayCenter_ = GetCenter(startTouches);
-    originalSceneCenter_ = GetCenter(originalSceneTouches_);
-    originalDisplayDistanceBetweenTouches_ = GetDistance(startTouches);
-
-//    printf("original Pan %f %f\n", originalPanX_, originalPanY_);
-//    printf("original Zoom %f \n", originalZoom_);
-//    printf("original distance %f \n", (float)originalDisplayDistanceBetweenTouches_);
-//    printf("original display touches 0 %f %f\n", startTouches[0].x, startTouches[0].y);
-//    printf("original display touches 1 %f %f\n", startTouches[1].x, startTouches[1].y);
-//    printf("original Scene center %f %f\n", originalSceneCenter_.x, originalSceneCenter_.y);
-
-    unsigned int height = that.GetView().GetDisplayHeight();
-
-    if (height <= 3)
-    {
-      idle_ = true;
-      LOG(WARNING) << "image is too small to zoom (current height = " << height << ")";
-    }
-    else
-    {
-      idle_ = false;
-      normalization_ = 1.0 / static_cast<double>(height - 1);
-    }
-
-  }
-
-
-  void PanZoomMouseTracker::Render(OrthancStone::CairoContext& context,
-                                   double zoom)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-  }
-
-
-  void PanZoomMouseTracker::MouseMove(int displayX,
-                                      int displayY,
-                                      double x,
-                                      double y,
-                                      const std::vector<Touch>& displayTouches,
-                                      const std::vector<Touch>& sceneTouches)
-  {
-    ViewportGeometry view = that_.GetView();
-
-//    printf("Display touches 0 %f %f\n", displayTouches[0].x, displayTouches[0].y);
-//    printf("Display touches 1 %f %f\n", displayTouches[1].x, displayTouches[1].y);
-//    printf("Scene touches 0 %f %f\n", sceneTouches[0].x, sceneTouches[0].y);
-//    printf("Scene touches 1 %f %f\n", sceneTouches[1].x, sceneTouches[1].y);
-
-//    printf("zoom = %f\n", view.GetZoom());
-    Touch currentSceneCenter = GetCenter(sceneTouches);
-    double panX = originalPanX_ + (currentSceneCenter.x - originalSceneCenter_.x) * view.GetZoom();
-    double panY = originalPanY_ + (currentSceneCenter.y - originalSceneCenter_.y) * view.GetZoom();
-
-    view.SetPan(panX, panY);
-
-    static const double MIN_ZOOM = -4;
-    static const double MAX_ZOOM = 4;
-
-    if (!idle_)
-    {
-      double currentDistanceBetweenTouches = GetDistance(displayTouches);
-
-      double dy = static_cast<double>(currentDistanceBetweenTouches - originalDisplayDistanceBetweenTouches_) * normalization_;  // In the range [-1,1]
-      double z;
-
-      // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
-      if (dy < -1.0)
-      {
-        z = MIN_ZOOM;
-      }
-      else if (dy > 1.0)
-      {
-        z = MAX_ZOOM;
-      }
-      else
-      {
-        z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0;
-      }
-
-      z = pow(2.0, z);
-
-      view.SetZoom(z * originalZoom_);
-    }
-
-    that_.SetView(view);
-  }
-}
--- a/Framework/Widgets/PanZoomMouseTracker.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
-
-namespace Deprecated
-{
-  class PanZoomMouseTracker : public IWorldSceneMouseTracker
-  {
-  private:
-    WorldSceneWidget&  that_;
-    std::vector<Touch> originalSceneTouches_;
-    Touch              originalSceneCenter_;
-    Touch              originalDisplayCenter_;
-    double             originalPanX_;
-    double             originalPanY_;
-    double             originalZoom_;
-    double             originalDisplayDistanceBetweenTouches_;
-    bool               idle_;
-    double             normalization_;
-
-  public:
-    PanZoomMouseTracker(WorldSceneWidget& that,
-                        const std::vector<Touch>& startTouches);
-    
-    virtual bool HasRender() const
-    {
-      return false;
-    }
-
-    virtual void MouseUp()
-    {
-    }
-
-    virtual void Render(OrthancStone::CairoContext& context,
-                        double zoom);
-
-    virtual void MouseMove(int displayX,
-                           int displayY,
-                           double x,
-                           double y,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
-  };
-}
--- a/Framework/Widgets/SliceViewerWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,654 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "SliceViewerWidget.h"
-
-#include "../Layers/SliceOutlineRenderer.h"
-#include "../Toolbox/GeometryToolbox.h"
-#include "Framework/Layers/FrameRenderer.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <boost/math/constants/constants.hpp>
-
-
-static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits<double>::epsilon();
-
-namespace Deprecated
-{
-  class SliceViewerWidget::Scene : public boost::noncopyable
-  {
-  private:
-    OrthancStone::CoordinateSystem3D            plane_;
-    double                        thickness_;
-    size_t                        countMissing_;
-    std::vector<ILayerRenderer*>  renderers_;
-
-  public:
-    void DeleteLayer(size_t index)
-    {
-      if (index >= renderers_.size())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-
-      assert(countMissing_ <= renderers_.size());
-
-      if (renderers_[index] != NULL)
-      {
-        assert(countMissing_ < renderers_.size());
-        delete renderers_[index];
-        renderers_[index] = NULL;
-        countMissing_++;
-      }
-    }
-
-    Scene(const OrthancStone::CoordinateSystem3D& plane,
-          double thickness,
-          size_t countLayers) :
-      plane_(plane),
-      thickness_(thickness),
-      countMissing_(countLayers),
-      renderers_(countLayers, NULL)
-    {
-      if (thickness <= 0)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-    }
-
-    ~Scene()
-    {
-      for (size_t i = 0; i < renderers_.size(); i++)
-      {
-        DeleteLayer(i);
-      }
-    }
-
-    void SetLayer(size_t index,
-                  ILayerRenderer* renderer)  // Takes ownership
-    {
-      if (renderer == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-
-      DeleteLayer(index);
-
-      renderers_[index] = renderer;
-      countMissing_--;
-    }
-
-    const OrthancStone::CoordinateSystem3D& GetPlane() const
-    {
-      return plane_;
-    }
-
-    bool HasRenderer(size_t index)
-    {
-      return renderers_[index] != NULL;
-    }
-
-    bool IsComplete() const
-    {
-      return countMissing_ == 0;
-    }
-
-    unsigned int GetCountMissing() const
-    {
-      return static_cast<unsigned int>(countMissing_);
-    }
-
-    bool RenderScene(OrthancStone::CairoContext& context,
-                     const ViewportGeometry& view,
-                     const OrthancStone::CoordinateSystem3D& viewportPlane)
-    {
-      bool fullQuality = true;
-      cairo_t *cr = context.GetObject();
-
-      for (size_t i = 0; i < renderers_.size(); i++)
-      {
-        if (renderers_[i] != NULL)
-        {
-          const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane();
-          
-          double x0, y0, x1, y1, x2, y2;
-          viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin());
-          viewportPlane.ProjectPoint(x1, y1, framePlane.GetOrigin() + framePlane.GetAxisX());
-          viewportPlane.ProjectPoint(x2, y2, framePlane.GetOrigin() + framePlane.GetAxisY());
-
-          /**
-           * Now we solve the system of linear equations Ax + b = x', given:
-           *   A [0 ; 0] + b = [x0 ; y0]
-           *   A [1 ; 0] + b = [x1 ; y1]
-           *   A [0 ; 1] + b = [x2 ; y2]
-           * <=>
-           *   b = [x0 ; y0]
-           *   A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0]
-           *   A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0]
-           * <=>
-           *   b = [x0 ; y0]
-           *   [a11 ; a21] = [x1 - x0 ; y1 - y0]
-           *   [a12 ; a22] = [x2 - x0 ; y2 - y0]
-           **/
-
-          cairo_matrix_t transform;
-          cairo_matrix_init(&transform, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0);
-
-          cairo_save(cr);
-          cairo_transform(cr, &transform);
-          
-          if (!renderers_[i]->RenderLayer(context, view))
-          {
-            cairo_restore(cr);
-            return false;
-          }
-
-          cairo_restore(cr);
-        }
-
-        if (renderers_[i] != NULL &&
-            !renderers_[i]->IsFullQuality())
-        {
-          fullQuality = false;
-        }
-      }
-
-      if (!fullQuality)
-      {
-        double x, y;
-        view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10);
-
-        cairo_translate(cr, x, y);
-
-#if 1
-        double s = 5.0 / view.GetZoom();
-        cairo_rectangle(cr, -s, -s, 2.0 * s, 2.0 * s);
-#else
-        // TODO Drawing filled circles makes WebAssembly crash!
-        cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2.0 * boost::math::constants::pi<double>());
-#endif
-        
-        cairo_set_line_width(cr, 2.0 / view.GetZoom());
-        cairo_set_source_rgb(cr, 1, 1, 1);
-        cairo_stroke_preserve(cr);
-        cairo_set_source_rgb(cr, 1, 0, 0);
-        cairo_fill(cr);
-      }
-
-      return true;
-    }
-
-    void SetLayerStyle(size_t index,
-                       const RenderStyle& style)
-    {
-      if (renderers_[index] != NULL)
-      {
-        renderers_[index]->SetLayerStyle(style);
-      }
-    }
-
-    bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const
-    {
-      bool isOpposite;
-      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                               plane.GetNormal(),
-                                                               plane_.GetNormal()))
-      {
-        return false;
-      }
-      else
-      {
-        double z = (plane_.ProjectAlongNormal(plane.GetOrigin()) -
-                    plane_.ProjectAlongNormal(plane_.GetOrigin()));
-
-        if (z < 0)
-        {
-          z = -z;
-        }
-
-        return z <= thickness_;
-      }
-    }
-
-    double GetThickness() const
-    {
-      return thickness_;
-    }
-  };
-
-  
-  bool SliceViewerWidget::LookupLayer(size_t& index /* out */,
-                                      const IVolumeSlicer& layer) const
-  {
-    LayersIndex::const_iterator found = layersIndex_.find(&layer);
-
-    if (found == layersIndex_.end())
-    {
-      return false;
-    }
-    else
-    {
-      index = found->second;
-      assert(index < layers_.size() &&
-             layers_[index] == &layer);
-      return true;
-    }
-  }
-
-
-  void SliceViewerWidget::GetLayerExtent(OrthancStone::Extent2D& extent,
-                                         IVolumeSlicer& source) const
-  {
-    extent.Reset();
-
-    std::vector<OrthancStone::Vector> points;
-    if (source.GetExtent(points, plane_))
-    {
-      for (size_t i = 0; i < points.size(); i++)
-      {
-        double x, y;
-        plane_.ProjectPoint(x, y, points[i]);
-        extent.AddPoint(x, y);
-      }
-    }
-  }
-
-
-  OrthancStone::Extent2D SliceViewerWidget::GetSceneExtent()
-  {
-    OrthancStone::Extent2D sceneExtent;
-
-    for (size_t i = 0; i < layers_.size(); i++)
-    {
-      assert(layers_[i] != NULL);
-      OrthancStone::Extent2D layerExtent;
-      GetLayerExtent(layerExtent, *layers_[i]);
-
-      sceneExtent.Union(layerExtent);
-    }
-
-    return sceneExtent;
-  }
-
-  
-  bool SliceViewerWidget::RenderScene(OrthancStone::CairoContext& context,
-                                      const ViewportGeometry& view)
-  {
-    if (currentScene_.get() != NULL)
-    {
-      return currentScene_->RenderScene(context, view, plane_);
-    }
-    else
-    {
-      return true;
-    }
-  }
-
-  
-  void SliceViewerWidget::ResetPendingScene()
-  {
-    double thickness;
-    if (pendingScene_.get() == NULL)
-    {
-      thickness = 1.0;
-    }
-    else
-    {
-      thickness = pendingScene_->GetThickness();
-    }
-    
-    pendingScene_.reset(new Scene(plane_, thickness, layers_.size()));
-  }
-  
-
-  void SliceViewerWidget::UpdateLayer(size_t index,
-                                      ILayerRenderer* renderer,
-                                      const OrthancStone::CoordinateSystem3D& plane)
-  {
-    LOG(INFO) << "Updating layer " << index;
-    
-    std::auto_ptr<ILayerRenderer> tmp(renderer);
-
-    if (renderer == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-    }
-
-    if (index >= layers_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    assert(layers_.size() == styles_.size());
-    renderer->SetLayerStyle(styles_[index]);
-
-    if (currentScene_.get() != NULL &&
-        currentScene_->ContainsPlane(plane))
-    {
-      currentScene_->SetLayer(index, tmp.release());
-      NotifyContentChanged();
-    }
-    else if (pendingScene_.get() != NULL &&
-             pendingScene_->ContainsPlane(plane))
-    {
-      pendingScene_->SetLayer(index, tmp.release());
-
-      if (currentScene_.get() == NULL ||
-          !currentScene_->IsComplete() ||
-          pendingScene_->IsComplete())
-      {
-        currentScene_ = pendingScene_;
-        NotifyContentChanged();
-      }
-    }
-  }
-
-  
-  SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, 
-                                       const std::string& name) :
-    WorldSceneWidget(name),
-    IObserver(broker),
-    IObservable(broker),
-    started_(false)
-  {
-    SetBackgroundCleared(true);
-  }
-  
-  
-  SliceViewerWidget::~SliceViewerWidget()
-  {
-    for (size_t i = 0; i < layers_.size(); i++)
-    {
-      delete layers_[i];
-    }
-  }
-  
-  void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer)
-  {
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage>
-                                   (*this, &SliceViewerWidget::OnGeometryReady));
-    // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryErrorMessage>(*this, &SliceViewerWidget::...));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::SliceContentChangedMessage>
-                                   (*this, &SliceViewerWidget::OnSliceChanged));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage>
-                                   (*this, &SliceViewerWidget::OnContentChanged));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage>
-                                   (*this, &SliceViewerWidget::OnLayerReady));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage>
-                                   (*this, &SliceViewerWidget::OnLayerError));
-  }
-
-
-  size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer)  // Takes ownership
-  {
-    if (layer == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-    }
-
-    size_t index = layers_.size();
-    layers_.push_back(layer);
-    styles_.push_back(RenderStyle());
-    layersIndex_[layer] = index;
-
-    ResetPendingScene();
-
-    ObserveLayer(*layer);
-
-    ResetChangedLayers();
-
-    return index;
-  }
-
-
-  void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer)  // Takes ownership
-  {
-    if (layer == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-    }
-
-    if (index >= layers_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    delete layers_[index];
-    layers_[index] = layer;
-    layersIndex_[layer] = index;
-
-    ResetPendingScene();
-
-    ObserveLayer(*layer);
-
-    InvalidateLayer(index);
-  }
-
-
-  void SliceViewerWidget::RemoveLayer(size_t index)
-  {
-    if (index >= layers_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    IVolumeSlicer* previousLayer = layers_[index];
-    layersIndex_.erase(layersIndex_.find(previousLayer));
-    layers_.erase(layers_.begin() + index);
-    changedLayers_.erase(changedLayers_.begin() + index);
-    styles_.erase(styles_.begin() + index);
-
-    delete layers_[index];
-
-    currentScene_->DeleteLayer(index);
-    ResetPendingScene();
-
-    NotifyContentChanged();
-  }
-
-
-  const RenderStyle& SliceViewerWidget::GetLayerStyle(size_t layer) const
-  {
-    if (layer >= layers_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    assert(layers_.size() == styles_.size());
-    return styles_[layer];
-  }
-  
-
-  void SliceViewerWidget::SetLayerStyle(size_t layer,
-                                        const RenderStyle& style)
-  {
-    if (layer >= layers_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    assert(layers_.size() == styles_.size());
-    styles_[layer] = style;
-
-    if (currentScene_.get() != NULL)
-    {
-      currentScene_->SetLayerStyle(layer, style);
-    }
-
-    if (pendingScene_.get() != NULL)
-    {
-      pendingScene_->SetLayerStyle(layer, style);
-    }
-
-    NotifyContentChanged();
-  }
-  
-
-  void SliceViewerWidget::SetSlice(const OrthancStone::CoordinateSystem3D& plane)
-  {
-    LOG(INFO) << "Setting slice origin: (" << plane.GetOrigin()[0]
-              << "," << plane.GetOrigin()[1]
-              << "," << plane.GetOrigin()[2] << ")";
-    
-    Deprecated::Slice displayedSlice(plane_, THIN_SLICE_THICKNESS);
-
-    //if (!displayedSlice.ContainsPlane(slice))
-    {
-      if (currentScene_.get() == NULL ||
-          (pendingScene_.get() != NULL &&
-           pendingScene_->IsComplete()))
-      {
-        currentScene_ = pendingScene_;
-      }
-
-      plane_ = plane;
-      ResetPendingScene();
-
-      InvalidateAllLayers();   // TODO Removing this line avoid loading twice the image in WASM
-    }
-
-    BroadcastMessage(DisplayedSliceMessage(*this, displayedSlice));
-  }
-
-
-  void SliceViewerWidget::OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message)
-  {
-    size_t i;
-    if (LookupLayer(i, message.GetOrigin()))
-    {
-      LOG(INFO) << ": Geometry ready for layer " << i << " in " << GetName();
-
-      changedLayers_[i] = true;
-      //layers_[i]->ScheduleLayerCreation(plane_);
-    }
-    BroadcastMessage(GeometryChangedMessage(*this));
-  }
-  
-
-  void SliceViewerWidget::InvalidateAllLayers()
-  {
-    for (size_t i = 0; i < layers_.size(); i++)
-    {
-      assert(layers_[i] != NULL);
-      changedLayers_[i] = true;
-      
-      //layers_[i]->ScheduleLayerCreation(plane_);
-    }
-  }
-
-
-  void SliceViewerWidget::InvalidateLayer(size_t layer)
-  {
-    if (layer >= layers_.size())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-    }
-
-    assert(layers_[layer] != NULL);
-    changedLayers_[layer] = true;
-
-    //layers_[layer]->ScheduleLayerCreation(plane_);
-  }
-
-
-  void SliceViewerWidget::OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message)
-  {
-    size_t index;
-    if (LookupLayer(index, message.GetOrigin()))
-    {
-      InvalidateLayer(index);
-    }
-    
-    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
-  }
-  
-
-  void SliceViewerWidget::OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message)
-  {
-    if (message.GetSlice().ContainsPlane(plane_))
-    {
-      size_t index;
-      if (LookupLayer(index, message.GetOrigin()))
-      {
-        InvalidateLayer(index);
-      }
-    }
-    
-    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
-  }
-  
-  
-  void SliceViewerWidget::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
-  {
-    size_t index;
-    if (LookupLayer(index, message.GetOrigin()))
-    {
-      LOG(INFO) << "Renderer ready for layer " << index;
-      UpdateLayer(index, message.CreateRenderer(), message.GetSlice());
-    }
-    
-    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
-  }
-
-
-  void SliceViewerWidget::OnLayerError(const IVolumeSlicer::LayerErrorMessage& message)
-  {
-    size_t index;
-    if (LookupLayer(index, message.GetOrigin()))
-    {
-      LOG(ERROR) << "Using error renderer on layer " << index;
-
-      // TODO
-      //UpdateLayer(index, new SliceOutlineRenderer(slice), slice);
-
-      BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
-    }
-  }
-
-
-  void SliceViewerWidget::ResetChangedLayers()
-  {
-    changedLayers_.resize(layers_.size());
-
-    for (size_t i = 0; i < changedLayers_.size(); i++)
-    {
-      changedLayers_[i] = false;
-    }
-  }
-
-
-  void SliceViewerWidget::DoAnimation()
-  {
-    assert(changedLayers_.size() <= layers_.size());
-    
-    for (size_t i = 0; i < changedLayers_.size(); i++)
-    {
-      if (changedLayers_[i])
-      {
-        layers_[i]->ScheduleLayerCreation(plane_);
-      }
-    }
-    
-    ResetChangedLayers();
-  }
-}
--- a/Framework/Widgets/SliceViewerWidget.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
-#include "../Layers/IVolumeSlicer.h"
-#include "../Toolbox/Extent2D.h"
-#include "../../Framework/Messages/IObserver.h"
-
-#include <map>
-
-namespace Deprecated
-{
-  class SliceViewerWidget :
-    public WorldSceneWidget,
-    public OrthancStone::IObserver,
-    public OrthancStone::IObservable
-  {
-  public:
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryChangedMessage, SliceViewerWidget);
-    ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, SliceViewerWidget);
-
-
-    // TODO - Use this message in ReferenceLineSource
-    class DisplayedSliceMessage : public OrthancStone::OriginMessage<SliceViewerWidget>
-    {
-      ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
-      
-    private:
-      const Deprecated::Slice& slice_;
-
-    public:
-      DisplayedSliceMessage(SliceViewerWidget& origin,
-                            const Deprecated::Slice& slice) :
-        OriginMessage(origin),
-        slice_(slice)
-      {
-      }
-
-      const Deprecated::Slice& GetSlice() const
-      {
-        return slice_;
-      }
-    };
-
-  private:
-    SliceViewerWidget(const SliceViewerWidget&);
-    SliceViewerWidget& operator=(const SliceViewerWidget&);
-
-    class Scene;
-    
-    typedef std::map<const IVolumeSlicer*, size_t>  LayersIndex;
-
-    bool                         started_;
-    LayersIndex                  layersIndex_;
-    std::vector<IVolumeSlicer*>  layers_;
-    std::vector<RenderStyle>     styles_;
-    OrthancStone::CoordinateSystem3D           plane_;
-    std::auto_ptr<Scene>         currentScene_;
-    std::auto_ptr<Scene>         pendingScene_;
-    std::vector<bool>            changedLayers_;
-
-    bool LookupLayer(size_t& index /* out */,
-                     const IVolumeSlicer& layer) const;
-
-    void GetLayerExtent(OrthancStone::Extent2D& extent,
-                        IVolumeSlicer& source) const;
-
-    void OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message);
-
-    virtual void OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message);
-
-    virtual void OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message);
-
-    virtual void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message);
-
-    virtual void OnLayerError(const IVolumeSlicer::LayerErrorMessage& message);
-
-    void ObserveLayer(IVolumeSlicer& source);
-
-    void ResetChangedLayers();
-
-  public:
-    SliceViewerWidget(OrthancStone::MessageBroker& broker, 
-                      const std::string& name);
-
-    virtual OrthancStone::Extent2D GetSceneExtent();
-
-  protected:
-    virtual bool RenderScene(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view);
-
-    void ResetPendingScene();
-
-    void UpdateLayer(size_t index,
-                     ILayerRenderer* renderer,
-                     const OrthancStone::CoordinateSystem3D& plane);
-
-    void InvalidateAllLayers();
-
-    void InvalidateLayer(size_t layer);
-    
-  public:
-    virtual ~SliceViewerWidget();
-
-    size_t AddLayer(IVolumeSlicer* layer);  // Takes ownership
-
-    void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership
-
-    void RemoveLayer(size_t layerIndex);
-
-    size_t GetLayerCount() const
-    {
-      return layers_.size();
-    }
-
-    const RenderStyle& GetLayerStyle(size_t layer) const;
-
-    void SetLayerStyle(size_t layer,
-                       const RenderStyle& style);
-
-    void SetSlice(const OrthancStone::CoordinateSystem3D& plane);
-
-    const OrthancStone::CoordinateSystem3D& GetSlice() const
-    {
-      return plane_;
-    }
-
-    virtual bool HasAnimation() const
-    {
-      return true;
-    }
-
-    virtual void DoAnimation();
-  };
-}
--- a/Framework/Widgets/TestCairoWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "TestCairoWidget.h"
-
-#include <stdio.h>
-
-
-namespace Deprecated
-{
-  namespace Samples
-  {
-    void TestCairoWidget::DoAnimation() 
-    {
-      value_ -= 0.01f;
-      if (value_ < 0)
-      {
-        value_ = 1;
-      }
-
-      NotifyContentChanged();
-    }
-
-
-    bool TestCairoWidget::RenderCairo(OrthancStone::CairoContext& context)
-    {
-      cairo_t* cr = context.GetObject();
-
-      cairo_set_source_rgb (cr, .3, 0, 0);
-      cairo_paint(cr);
-
-      cairo_set_source_rgb(cr, 0, 1, 0);
-      cairo_rectangle(cr, width_ / 4, height_ / 4, width_ / 2, height_ / 2);
-      cairo_set_line_width(cr, 1.0);
-      cairo_fill(cr);
-
-      cairo_set_source_rgb(cr, 0, 1, value_);
-      cairo_rectangle(cr, width_ / 2 - 50, height_ / 2 - 50, 100, 100);
-      cairo_fill(cr);
-
-      return true;
-    }
-
-
-    void TestCairoWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context,
-                                               int x,
-                                               int y)
-    {
-      cairo_t* cr = context.GetObject();
-
-      cairo_set_source_rgb (cr, 1, 0, 0);
-      cairo_rectangle(cr, x - 5, y - 5, 10, 10);
-      cairo_set_line_width(cr, 1.0);
-      cairo_stroke(cr);
-
-      char buf[64];
-      sprintf(buf, "(%d,%d)", x, y);
-      UpdateStatusBar(buf);
-    }
-
-
-    TestCairoWidget::TestCairoWidget(const std::string& name, bool animate) :
-      CairoWidget(name),
-      width_(0),
-      height_(0),
-      value_(1),
-      animate_(animate)
-    {
-    }
-
-
-    void TestCairoWidget::SetSize(unsigned int width, 
-                                  unsigned int height)
-    {
-      CairoWidget::SetSize(width, height);
-      width_ = width;
-      height_ = height;
-    }
- 
-
-    IMouseTracker* TestCairoWidget::CreateMouseTracker(OrthancStone::MouseButton button,
-                                                       int x,
-                                                       int y,
-                                                       OrthancStone::KeyboardModifiers modifiers,
-                                                       const std::vector<Touch>& touches)
-    {
-      UpdateStatusBar("Click");
-      return NULL;
-    }
-
-
-    void TestCairoWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
-                                     int x,
-                                     int y,
-                                     OrthancStone::KeyboardModifiers modifiers) 
-    {
-      UpdateStatusBar(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
-    }
-
-    
-    void TestCairoWidget::KeyPressed(OrthancStone::KeyboardKeys key,
-                                     char keyChar,
-                                     OrthancStone::KeyboardModifiers modifiers)
-    {
-      UpdateStatusBar("Key pressed: \"" + std::string(1, keyChar) + "\"");
-    }
-  }
-}
--- a/Framework/Widgets/TestCairoWidget.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CairoWidget.h"
-
-namespace Deprecated
-{
-  namespace Samples
-  {
-    class TestCairoWidget : public CairoWidget
-    {
-    private:
-      unsigned int  width_;
-      unsigned int  height_;
-      float         value_;
-      bool          animate_;
-
-    protected:
-      virtual bool RenderCairo(OrthancStone::CairoContext& context);
-
-      virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
-                                        int x,
-                                        int y);
-
-    public:
-      TestCairoWidget(const std::string& name, bool animate);
-
-      virtual void SetSize(unsigned int width, 
-                           unsigned int height);
- 
-      virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
-                                                int x,
-                                                int y,
-                                                OrthancStone::KeyboardModifiers modifiers,
-                                                const std::vector<Touch>& touches);
-
-      virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                              int x,
-                              int y,
-                              OrthancStone::KeyboardModifiers modifiers);
-    
-      virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                              char keyChar,
-                              OrthancStone::KeyboardModifiers modifiers);
-
-      virtual bool HasAnimation() const
-      {
-        return animate_;
-      }
-      
-      virtual void DoAnimation();
-
-      virtual bool HasRenderMouseOver()
-      {
-        return true;
-      }
-    };
-  }
-}
--- a/Framework/Widgets/TestWorldSceneWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "TestWorldSceneWidget.h"
-
-#include <Core/OrthancException.h>
-
-#include <math.h>
-#include <stdio.h>
-
-namespace Deprecated
-{
-  namespace Samples
-  {
-    class TestWorldSceneWidget::Interactor : public IWorldSceneInteractor
-    {
-    public:
-      virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                          const ViewportGeometry& view,
-                                                          OrthancStone::MouseButton button,
-                                                          OrthancStone::KeyboardModifiers modifiers,
-                                                          int viewportX,
-                                                          int viewportY,
-                                                          double x,
-                                                          double y,
-                                                          IStatusBar* statusBar,
-                                                          const std::vector<Touch>& touches)
-      {
-        if (statusBar)
-        {
-          char buf[64];
-          sprintf(buf, "X = %0.2f, Y = %0.2f", x, y);
-          statusBar->SetMessage(buf);
-        }
-
-        return NULL;
-      }
-
-      virtual void MouseOver(OrthancStone::CairoContext& context,
-                             WorldSceneWidget& widget,
-                             const ViewportGeometry& view,
-                             double x,
-                             double y,
-                             IStatusBar* statusBar)
-      {
-        double S = 0.5;
-
-        if (fabs(x) <= S &&
-            fabs(y) <= S)
-        {
-          cairo_t* cr = context.GetObject();
-          cairo_set_source_rgb(cr, 1, 0, 0);
-          cairo_rectangle(cr, -S, -S , 2.0 * S, 2.0 * S);
-          cairo_set_line_width(cr, 1.0 / view.GetZoom());
-          cairo_stroke(cr);
-        }
-      }
-
-      virtual void MouseWheel(WorldSceneWidget& widget,
-                              OrthancStone::MouseWheelDirection direction,
-                              OrthancStone::KeyboardModifiers modifiers,
-                              IStatusBar* statusBar)
-      {
-        if (statusBar)
-        {
-          statusBar->SetMessage(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up");
-        }
-      }
-
-      virtual void KeyPressed(WorldSceneWidget& widget,
-                              OrthancStone::KeyboardKeys key,
-                              char keyChar,
-                              OrthancStone::KeyboardModifiers modifiers,
-                              IStatusBar* statusBar)
-      {
-        if (statusBar)
-        {
-          statusBar->SetMessage("Key pressed: \"" + std::string(1, keyChar) + "\"");
-        }
-      }
-    };
-
-
-    bool TestWorldSceneWidget::RenderScene(OrthancStone::CairoContext& context,
-                                           const ViewportGeometry& view)
-    {
-      cairo_t* cr = context.GetObject();
-
-      // Clear background
-      cairo_set_source_rgb(cr, 0, 0, 0);
-      cairo_paint(cr);
-
-      float color = static_cast<float>(count_ % 16) / 15.0f;
-      cairo_set_source_rgb(cr, 0, 1.0f - color, color);
-      cairo_rectangle(cr, -10, -.5, 20, 1);
-      cairo_fill(cr);
-
-      return true;
-    }
-
-
-    TestWorldSceneWidget::TestWorldSceneWidget(const std::string& name, bool animate) :
-      WorldSceneWidget(name),
-      interactor_(new Interactor),
-      animate_(animate),
-      count_(0)
-    {
-      SetInteractor(*interactor_);
-    }
-
-
-    OrthancStone::Extent2D TestWorldSceneWidget::GetSceneExtent()
-    {
-      return OrthancStone::Extent2D(-10, -.5, 10, .5);
-    }
-
-
-    void TestWorldSceneWidget::DoAnimation()
-    {
-      if (animate_)
-      {
-        count_++;
-        NotifyContentChanged();
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-    }
-  }
-}
--- a/Framework/Widgets/TestWorldSceneWidget.h	Tue May 21 13:27:54 2019 +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-2019 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 "WorldSceneWidget.h"
-
-#include <memory>
-
-namespace Deprecated
-{
-  namespace Samples
-  {
-    class TestWorldSceneWidget : public WorldSceneWidget
-    {
-    private:
-      class Interactor;
-
-      std::auto_ptr<Interactor>   interactor_;
-      bool                        animate_;
-      unsigned int                count_;
-
-    protected:
-      virtual bool RenderScene(OrthancStone::CairoContext& context,
-                               const ViewportGeometry& view);
-
-    public:
-      TestWorldSceneWidget(const std::string& name, bool animate);
-
-      virtual OrthancStone::Extent2D GetSceneExtent();
-
-      virtual bool HasAnimation() const
-      {
-        return animate_;
-      }
-
-      virtual void DoAnimation();
-
-      virtual bool HasRenderMouseOver()
-      {
-        return true;
-      }
-    };
-  }
-}
--- a/Framework/Widgets/WidgetBase.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WidgetBase.h"
-
-#include <Core/OrthancException.h>
-#include <Core/Images/ImageProcessing.h>
-#include <Core/Logging.h>
-
-namespace Deprecated
-{
-  void WidgetBase::NotifyContentChanged()
-  {
-    if (parent_ != NULL)
-    {
-      parent_->NotifyContentChanged();
-    }
-
-    if (viewport_ != NULL)
-    {
-      viewport_->NotifyBackgroundChanged();
-    }
-  }
-
-
-  void WidgetBase::SetParent(IWidget& parent)
-  {
-    if (parent_ != NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      parent_ = &parent;
-    }
-  }    
-
-  
-  void WidgetBase::ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const 
-  {
-    // Clear the background using Orthanc
-
-    if (backgroundCleared_)
-    {
-      Orthanc::ImageProcessing::Set(target, 
-                                    backgroundColor_[0],
-                                    backgroundColor_[1],
-                                    backgroundColor_[2],
-                                    255 /* alpha */);
-    }
-  }
-
-
-  void WidgetBase::ClearBackgroundCairo(OrthancStone::CairoContext& context) const
-  {
-    // Clear the background using Cairo
-
-    if (IsBackgroundCleared())
-    {
-      uint8_t red, green, blue;
-      GetBackgroundColor(red, green, blue);
-
-      context.SetSourceColor(red, green, blue);
-      cairo_paint(context.GetObject());
-    }
-  }
-
-
-  void WidgetBase::ClearBackgroundCairo(Orthanc::ImageAccessor& target) const
-  {
-    OrthancStone::CairoSurface surface(target, false /* no alpha */);
-    OrthancStone::CairoContext context(surface);
-    ClearBackgroundCairo(context);
-  }
-
-
-  void WidgetBase::UpdateStatusBar(const std::string& message)
-  {
-    if (statusBar_ != NULL)
-    {
-      statusBar_->SetMessage(message);
-    }
-  }
-
-
-  WidgetBase::WidgetBase(const std::string& name) :
-    parent_(NULL),
-    viewport_(NULL),
-    statusBar_(NULL),
-    backgroundCleared_(false),
-    transmitMouseOver_(false),
-    name_(name)
-  {
-    backgroundColor_[0] = 0;
-    backgroundColor_[1] = 0;
-    backgroundColor_[2] = 0;
-  }
-
-
-  void WidgetBase::SetViewport(WidgetViewport& viewport)
-  {
-    if (viewport_ != NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      viewport_ = &viewport;
-    }
-  }
-
-  
-  void WidgetBase::SetBackgroundColor(uint8_t red,
-                                      uint8_t green,
-                                      uint8_t blue)
-  {
-    backgroundColor_[0] = red;
-    backgroundColor_[1] = green;
-    backgroundColor_[2] = blue;
-  }
-
-  void WidgetBase::GetBackgroundColor(uint8_t& red,
-                                      uint8_t& green,
-                                      uint8_t& blue) const
-  {
-    red = backgroundColor_[0];
-    green = backgroundColor_[1];
-    blue = backgroundColor_[2];
-  }
-
-
-  bool WidgetBase::Render(Orthanc::ImageAccessor& surface)
-  {
-#if 0
-    ClearBackgroundOrthanc(surface);
-#else
-    ClearBackgroundCairo(surface);  // Faster than Orthanc
-#endif
-
-    return true;
-  }
-
-  
-  void WidgetBase::DoAnimation()
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-  }
-}
--- a/Framework/Widgets/WidgetBase.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IWidget.h"
-
-#include "../Viewport/CairoContext.h"
-#include "../Viewport/WidgetViewport.h"
-
-namespace Deprecated
-{
-  class WidgetBase : public IWidget
-  {
-  private:
-    IWidget*         parent_;
-    WidgetViewport*  viewport_;
-    IStatusBar*      statusBar_;
-    bool             backgroundCleared_;
-    uint8_t          backgroundColor_[3];
-    bool             transmitMouseOver_;
-    std::string      name_;
-
-  protected:
-    void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const;
-
-    void ClearBackgroundCairo(OrthancStone::CairoContext& context) const;
-
-    void ClearBackgroundCairo(Orthanc::ImageAccessor& target) const;
-
-    void UpdateStatusBar(const std::string& message);
-
-    IStatusBar* GetStatusBar() const
-    {
-      return statusBar_;
-    }
-
-  public:
-    WidgetBase(const std::string& name);
-
-    virtual void FitContent()
-    {
-    }
-  
-    virtual void SetParent(IWidget& parent);
-    
-    virtual void SetViewport(WidgetViewport& viewport);
-
-    void SetBackgroundCleared(bool clear)
-    {
-      backgroundCleared_ = clear;
-    }
-
-    bool IsBackgroundCleared() const
-    {
-      return backgroundCleared_;
-    }
-
-    void SetTransmitMouseOver(bool transmit)
-    {
-      transmitMouseOver_ = transmit;
-    }
-
-    void SetBackgroundColor(uint8_t red,
-                            uint8_t green,
-                            uint8_t blue);
-
-    void GetBackgroundColor(uint8_t& red,
-                            uint8_t& green,
-                            uint8_t& blue) const;
-
-    virtual void SetStatusBar(IStatusBar& statusBar)
-    {
-      statusBar_ = &statusBar;
-    }
-
-    virtual bool Render(Orthanc::ImageAccessor& surface);
-
-    virtual bool HasAnimation() const
-    {
-      return false;
-    }
-
-    virtual void DoAnimation();
-
-    virtual bool HasRenderMouseOver()
-    {
-      return transmitMouseOver_;
-    }
-
-    virtual void NotifyContentChanged();
-
-    const std::string& GetName() const
-    {
-      return name_;
-    }
-
-  };
-}
--- a/Framework/Widgets/WorldSceneWidget.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
-
-#include "PanMouseTracker.h"
-#include "ZoomMouseTracker.h"
-#include "PanZoomMouseTracker.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-#include <math.h>
-#include <memory>
-#include <cassert>
-
-namespace Deprecated
-{
-  // this is an adapter between a IWorldSceneMouseTracker
-  // that is tracking a mouse in scene coordinates/mm and
-  // an IMouseTracker that is tracking a mouse
-  // in screen coordinates/pixels.
-  class WorldSceneWidget::SceneMouseTracker : public IMouseTracker
-  {
-  private:
-    ViewportGeometry                        view_;
-    std::auto_ptr<IWorldSceneMouseTracker>  tracker_;
-
-  public:
-    SceneMouseTracker(const ViewportGeometry& view,
-                      IWorldSceneMouseTracker* tracker) :
-      view_(view),
-      tracker_(tracker)
-    {
-      if (tracker == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-    }
-
-    virtual void Render(Orthanc::ImageAccessor& target)
-    {
-      if (tracker_->HasRender())
-      {
-        OrthancStone::CairoSurface surface(target, false /* no alpha */);
-        OrthancStone::CairoContext context(surface);
-        view_.ApplyTransform(context);
-        tracker_->Render(context, view_.GetZoom());
-      }
-    }
-
-    virtual void MouseUp()
-    {
-      tracker_->MouseUp();
-    }
-
-    virtual void MouseMove(int x,
-                           int y,
-                           const std::vector<Touch>& displayTouches)
-    {
-      double sceneX, sceneY;
-      view_.MapPixelCenterToScene(sceneX, sceneY, x, y);
-
-      std::vector<Touch> sceneTouches;
-      for (size_t t = 0; t < displayTouches.size(); t++)
-      {
-        double sx, sy;
-        
-        view_.MapPixelCenterToScene(
-          sx, sy, (int)displayTouches[t].x, (int)displayTouches[t].y);
-        
-        sceneTouches.push_back(
-          Touch(static_cast<float>(sx), static_cast<float>(sy)));
-      }
-      tracker_->MouseMove(x, y, sceneX, sceneY, displayTouches, sceneTouches);
-    }
-  };
-
-
-  bool WorldSceneWidget::RenderCairo(OrthancStone::CairoContext& context)
-  {
-    view_.ApplyTransform(context);
-    return RenderScene(context, view_);
-  }
-
-
-  void WorldSceneWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context,
-                                              int x,
-                                              int y)
-  {
-    ViewportGeometry view = GetView();
-    view.ApplyTransform(context);
-
-    double sceneX, sceneY;
-    view.MapPixelCenterToScene(sceneX, sceneY, x, y);
-
-    if (interactor_)
-    {
-      interactor_->MouseOver(context, *this, view, sceneX, sceneY, GetStatusBar());
-    }
-  }
-
-
-  void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view)
-  {
-    view.SetSceneExtent(GetSceneExtent());
-  }
-
-
-  void WorldSceneWidget::SetSize(unsigned int width,
-                                 unsigned int height)
-  {
-    CairoWidget::SetSize(width, height);
-    view_.SetDisplaySize(width, height);
-  }
-
-
-  void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor)
-  {
-    interactor_ = &interactor;
-  }
-
-
-  void WorldSceneWidget::FitContent()
-  {
-    SetSceneExtent(view_);
-    view_.FitContent();
-
-    NotifyContentChanged();
-  }
-
-
-  void WorldSceneWidget::SetView(const ViewportGeometry& view)
-  {
-    view_ = view;
-
-    NotifyContentChanged();
-  }
-
-
-  IMouseTracker* WorldSceneWidget::CreateMouseTracker(OrthancStone::MouseButton button,
-                                                      int x,
-                                                      int y,
-                                                      OrthancStone::KeyboardModifiers modifiers,
-                                                      const std::vector<Touch>& touches)
-  {
-    double sceneX, sceneY;
-    view_.MapPixelCenterToScene(sceneX, sceneY, x, y);
-
-    // asks the Widget Interactor to provide a mouse tracker
-    std::auto_ptr<IWorldSceneMouseTracker> tracker;
-
-    if (interactor_)
-    {
-      tracker.reset(interactor_->CreateMouseTracker(*this, view_, button, modifiers, x, y, sceneX, sceneY, GetStatusBar(), touches));
-    }
-    
-    if (tracker.get() != NULL)
-    {
-      return new SceneMouseTracker(view_, tracker.release());
-    }
-    else if (hasDefaultMouseEvents_)
-    {
-      printf("has default mouse events\n");
-      if (touches.size() == 2)
-      {
-        printf("2 touches !\n");
-        return new SceneMouseTracker(view_, new PanZoomMouseTracker(*this, touches));
-      }
-      else
-      {
-        switch (button)
-        {
-          case OrthancStone::MouseButton_Middle:
-            return new SceneMouseTracker(view_, new PanMouseTracker(*this, x, y));
-
-          case OrthancStone::MouseButton_Right:
-            return new SceneMouseTracker(view_, new ZoomMouseTracker(*this, x, y));
-
-          default:
-            return NULL;
-        }
-      }
-    }
-    else
-    {
-      return NULL;
-    }
-  }
-
-
-  void WorldSceneWidget::MouseWheel(OrthancStone::MouseWheelDirection direction,
-                                    int x,
-                                    int y,
-                                    OrthancStone::KeyboardModifiers modifiers)
-  {
-    if (interactor_)
-    {
-      interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar());
-    }
-  }
-
-
-  void WorldSceneWidget::KeyPressed(OrthancStone::KeyboardKeys key,
-                                    char keyChar,
-                                    OrthancStone::KeyboardModifiers modifiers)
-  {
-    if (interactor_)
-    {
-      interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar());
-    }
-  }
-}
--- a/Framework/Widgets/WorldSceneWidget.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "CairoWidget.h"
-#include "IWorldSceneInteractor.h"
-
-#include "../Toolbox/ViewportGeometry.h"
-
-namespace Deprecated
-{
-  class WorldSceneWidget : public CairoWidget
-  {
-  private:
-    class SceneMouseTracker;
-
-    ViewportGeometry       view_;
-    IWorldSceneInteractor* interactor_;
-    bool                   hasDefaultMouseEvents_;
-
-  protected:
-    virtual OrthancStone::Extent2D GetSceneExtent() = 0;
-
-    virtual bool RenderScene(OrthancStone::CairoContext& context,
-                             const ViewportGeometry& view) = 0;
-
-    // From CairoWidget
-    virtual bool RenderCairo(OrthancStone::CairoContext& context);
-
-    // From CairoWidget
-    virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context,
-                                      int x,
-                                      int y);
-
-    void SetSceneExtent(ViewportGeometry& geometry);
-
-  public:
-    WorldSceneWidget(const std::string& name) :
-      CairoWidget(name),
-      interactor_(NULL),
-      hasDefaultMouseEvents_(true)
-    {
-    }
-
-    void SetDefaultMouseEvents(bool value)
-    {
-      hasDefaultMouseEvents_ = value;
-    }
-
-    bool HasDefaultMouseEvents() const
-    {
-      return hasDefaultMouseEvents_;
-    }
-
-    void SetInteractor(IWorldSceneInteractor& interactor);
-
-    void SetView(const ViewportGeometry& view);
-
-    const ViewportGeometry& GetView() const
-    {
-      return view_;
-    }
-
-    virtual void SetSize(unsigned int width,
-                         unsigned int height);
-
-    virtual void FitContent();
-
-    virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button,
-                                              int x,
-                                              int y,
-                                              OrthancStone::KeyboardModifiers modifiers,
-                                              const std::vector<Touch>& touches);
-
-    virtual void MouseWheel(OrthancStone::MouseWheelDirection direction,
-                            int x,
-                            int y,
-                            OrthancStone::KeyboardModifiers modifiers);
-
-    virtual void KeyPressed(OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers);
-  };
-}
--- a/Framework/Widgets/ZoomMouseTracker.cpp	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "ZoomMouseTracker.h"
-
-#include <Core/Logging.h>
-#include <Core/OrthancException.h>
-
-namespace Deprecated
-{
-  ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that,
-                                     int x,
-                                     int y) :
-    that_(that),
-    originalZoom_(that.GetView().GetZoom()),
-    downX_(x),
-    downY_(y)
-  {
-    that.GetView().MapPixelCenterToScene(centerX_, centerY_, x, y);
-
-    unsigned int height = that.GetView().GetDisplayHeight();
-      
-    if (height <= 3)
-    {
-      idle_ = true;
-      LOG(WARNING) << "image is too small to zoom (current height = " << height << ")";
-    }
-    else
-    {
-      idle_ = false;
-      normalization_ = 1.0 / static_cast<double>(height - 1);
-    }
-  }
-    
-
-  void ZoomMouseTracker::Render(OrthancStone::CairoContext& context,
-                                double zoom)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-  }
-
-
-  void ZoomMouseTracker::MouseMove(int displayX,
-                                   int displayY,
-                                   double x,
-                                   double y,
-                                   const std::vector<Touch>& displayTouches,
-                                   const std::vector<Touch>& sceneTouches)
-  {
-    static const double MIN_ZOOM = -4;
-    static const double MAX_ZOOM = 4;
-
-      
-    if (!idle_)
-    {
-      double dy = static_cast<double>(displayY - downY_) * normalization_;  // In the range [-1,1]
-      double z;
-
-      // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM]
-      if (dy < -1.0)
-      {
-        z = MIN_ZOOM;
-      }
-      else if (dy > 1.0)
-      {
-        z = MAX_ZOOM;
-      }
-      else
-      {
-        z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0;
-      }
-
-      z = pow(2.0, z);
-
-      ViewportGeometry view = that_.GetView();
-        
-      view.SetZoom(z * originalZoom_);
-        
-      // Correct the pan so that the original click point is kept at
-      // the same location on the display
-      double panX, panY;
-      view.GetPan(panX, panY);
-
-      int tx, ty;
-      view.MapSceneToDisplay(tx, ty, centerX_, centerY_);
-      view.SetPan(panX + static_cast<double>(downX_ - tx),
-                  panY + static_cast<double>(downY_ - ty));
-        
-      that_.SetView(view);
-    }
-  }
-}
--- a/Framework/Widgets/ZoomMouseTracker.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "WorldSceneWidget.h"
-
-namespace Deprecated
-{
-  class ZoomMouseTracker : public IWorldSceneMouseTracker
-  {
-  private:
-    WorldSceneWidget&  that_;
-    double             originalZoom_;
-    int                downX_;
-    int                downY_;
-    double             centerX_;
-    double             centerY_;
-    bool               idle_;
-    double             normalization_;
-    
-  public:
-    ZoomMouseTracker(WorldSceneWidget& that,
-                     int x,
-                     int y);
-    
-    virtual bool HasRender() const
-    {
-      return false;
-    }
-
-    virtual void MouseUp()
-    {
-    }
-
-    virtual void Render(OrthancStone::CairoContext& context,
-                        double zoom);
-
-    virtual void MouseMove(int displayX,
-                           int displayY,
-                           double x,
-                           double y,
-                           const std::vector<Touch>& displayTouches,
-                           const std::vector<Touch>& sceneTouches);
-  };
-}
--- a/Framework/dev.h	Tue May 21 13:27:54 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,958 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "Layers/FrameRenderer.h"
-#include "Layers/LineLayerRenderer.h"
-#include "Layers/SliceOutlineRenderer.h"
-#include "Toolbox/DownloadStack.h"
-#include "Toolbox/GeometryToolbox.h"
-#include "Toolbox/OrthancSlicesLoader.h"
-#include "Volumes/ImageBuffer3D.h"
-#include "Volumes/ISlicedVolume.h"
-#include "Widgets/SliceViewerWidget.h"
-
-#include <Core/Logging.h>
-#include <Core/Images/ImageProcessing.h>
-#include <Core/OrthancException.h>
-
-#include <boost/math/special_functions/round.hpp>
-
-
-namespace Deprecated
-{
-  // TODO: Handle errors while loading
-  class OrthancVolumeImage :
-    public ISlicedVolume,
-    public OrthancStone::IObserver
-  {
-  private:
-    OrthancSlicesLoader           loader_;
-    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
-    std::auto_ptr<DownloadStack>  downloadStack_;
-    bool                          computeRange_;
-    size_t                        pendingSlices_;
-
-    void ScheduleSliceDownload()
-    {
-      assert(downloadStack_.get() != NULL);
-
-      unsigned int slice;
-      if (downloadStack_->Pop(slice))
-      {
-        loader_.ScheduleLoadSliceImage(slice, OrthancStone::SliceImageQuality_Jpeg90);
-      }
-    }
-
-
-    static bool IsCompatible(const Slice& a,
-                             const Slice& b)
-    {
-      if (!OrthancStone::GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(),
-                                                     b.GetGeometry().GetNormal()))
-      {
-        LOG(ERROR) << "A slice in the volume image is not parallel to the others.";
-        return false;
-      }
-
-      if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat())
-      {
-        LOG(ERROR) << "The pixel format changes across the slices of the volume image.";
-        return false;
-      }
-
-      if (a.GetWidth() != b.GetWidth() ||
-          a.GetHeight() != b.GetHeight())
-      {
-        LOG(ERROR) << "The slices dimensions (width/height) are varying throughout the volume image";
-        return false;
-      }
-
-      if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
-          !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
-      {
-        LOG(ERROR) << "The pixel spacing of the slices change across the volume image";
-        return false;
-      }
-
-      return true;
-    }
-
-
-    static double GetDistance(const Slice& a,
-                              const Slice& b)
-    {
-      return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) -
-                  a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin()));
-    }
-
-
-    void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
-    {
-      assert(&message.GetOrigin() == &loader_);
-
-      if (loader_.GetSlicesCount() == 0)
-      {
-        LOG(ERROR) << "Empty volume image";
-        BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
-        return;
-      }
-
-      for (size_t i = 1; i < loader_.GetSlicesCount(); i++)
-      {
-        if (!IsCompatible(loader_.GetSlice(0), loader_.GetSlice(i)))
-        {
-          BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
-          return;
-        }
-      }
-
-      double spacingZ;
-
-      if (loader_.GetSlicesCount() > 1)
-      {
-        spacingZ = GetDistance(loader_.GetSlice(0), loader_.GetSlice(1));
-      }
-      else
-      {
-        // This is a volume with one single slice: Choose a dummy
-        // z-dimension for voxels
-        spacingZ = 1;
-      }
-
-      for (size_t i = 1; i < loader_.GetSlicesCount(); i++)
-      {
-        if (!OrthancStone::LinearAlgebra::IsNear(spacingZ, GetDistance(loader_.GetSlice(i - 1), loader_.GetSlice(i)),
-                                                 0.001 /* this is expressed in mm */))
-        {
-          LOG(ERROR) << "The distance between successive slices is not constant in a volume image";
-          BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
-          return;
-        }
-      }
-
-      unsigned int width = loader_.GetSlice(0).GetWidth();
-      unsigned int height = loader_.GetSlice(0).GetHeight();
-      Orthanc::PixelFormat format = loader_.GetSlice(0).GetConverter().GetExpectedPixelFormat();
-      LOG(INFO) << "Creating a volume image of size " << width << "x" << height
-                << "x" << loader_.GetSlicesCount() << " in " << Orthanc::EnumerationToString(format);
-
-      image_.reset(new OrthancStone::ImageBuffer3D(format, width, height, static_cast<unsigned int>(loader_.GetSlicesCount()), computeRange_));
-      image_->GetGeometry().SetAxialGeometry(loader_.GetSlice(0).GetGeometry());
-      image_->GetGeometry().SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(),
-                                               loader_.GetSlice(0).GetPixelSpacingY(), spacingZ);
-      image_->Clear();
-
-      downloadStack_.reset(new DownloadStack(static_cast<unsigned int>(loader_.GetSlicesCount())));
-      pendingSlices_ = loader_.GetSlicesCount();
-
-      for (unsigned int i = 0; i < 4; i++)  // Limit to 4 simultaneous downloads
-      {
-        ScheduleSliceDownload();
-      }
-
-      // TODO Check the DicomFrameConverter are constant
-
-      BroadcastMessage(ISlicedVolume::GeometryReadyMessage(*this));
-    }
-
-
-    void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
-    {
-      assert(&message.GetOrigin() == &loader_);
-
-      LOG(ERROR) << "Unable to download a volume image";
-      BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this));
-    }
-
-
-    void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
-    {
-      assert(&message.GetOrigin() == &loader_);
-
-      {
-        OrthancStone::ImageBuffer3D::SliceWriter writer(*image_, OrthancStone::VolumeProjection_Axial, message.GetSliceIndex());
-        Orthanc::ImageProcessing::Copy(writer.GetAccessor(), message.GetImage());
-      }
-
-      BroadcastMessage(ISlicedVolume::SliceContentChangedMessage
-                       (*this, message.GetSliceIndex(), message.GetSlice()));
-
-      if (pendingSlices_ == 1)
-      {
-        BroadcastMessage(ISlicedVolume::VolumeReadyMessage(*this));
-        pendingSlices_ = 0;
-      }
-      else if (pendingSlices_ > 1)
-      {
-        pendingSlices_ -= 1;
-      }
-
-      ScheduleSliceDownload();
-    }
-
-
-    void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
-    {
-      assert(&message.GetOrigin() == &loader_);
-
-      LOG(ERROR) << "Cannot download slice " << message.GetSliceIndex() << " in a volume image";
-      ScheduleSliceDownload();
-    }
-
-
-  public:
-    OrthancVolumeImage(OrthancStone::MessageBroker& broker,
-                       OrthancApiClient& orthanc,
-                       bool computeRange) :
-      ISlicedVolume(broker),
-      IObserver(broker),
-      loader_(broker, orthanc),
-      computeRange_(computeRange),
-      pendingSlices_(0)
-    {
-      loader_.RegisterObserverCallback(
-        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryReadyMessage>
-        (*this, &OrthancVolumeImage::OnSliceGeometryReady));
-
-      loader_.RegisterObserverCallback(
-        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceGeometryErrorMessage>
-        (*this, &OrthancVolumeImage::OnSliceGeometryError));
-
-      loader_.RegisterObserverCallback(
-        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageReadyMessage>
-        (*this, &OrthancVolumeImage::OnSliceImageReady));
-
-      loader_.RegisterObserverCallback(
-        new OrthancStone::Callable<OrthancVolumeImage, OrthancSlicesLoader::SliceImageErrorMessage>
-        (*this, &OrthancVolumeImage::OnSliceImageError));
-    }
-
-    void ScheduleLoadSeries(const std::string& seriesId)
-    {
-      loader_.ScheduleLoadSeries(seriesId);
-    }
-
-    void ScheduleLoadInstance(const std::string& instanceId)
-    {
-      loader_.ScheduleLoadInstance(instanceId);
-    }
-
-    void ScheduleLoadFrame(const std::string& instanceId,
-                           unsigned int frame)
-    {
-      loader_.ScheduleLoadFrame(instanceId, frame);
-    }
-
-    virtual size_t GetSlicesCount() const
-    {
-      return loader_.GetSlicesCount();
-    }
-
-    virtual const Slice& GetSlice(size_t index) const
-    {
-      return loader_.GetSlice(index);
-    }
-
-    OrthancStone::ImageBuffer3D& GetImage() const
-    {
-      if (image_.get() == NULL)
-      {
-        // The geometry is not ready yet
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        return *image_;
-      }
-    }
-
-    bool FitWindowingToRange(RenderStyle& style,
-                             const DicomFrameConverter& converter) const
-    {
-      if (image_.get() == NULL)
-      {
-        return false;
-      }
-      else
-      {
-        return image_->FitWindowingToRange(style, converter);
-      }
-    }
-  };
-
-
-  class VolumeImageGeometry
-  {
-  private:
-    unsigned int         width_;
-    unsigned int         height_;
-    size_t               depth_;
-    double               pixelSpacingX_;
-    double               pixelSpacingY_;
-    double               sliceThickness_;
-    OrthancStone::CoordinateSystem3D   reference_;
-    DicomFrameConverter  converter_;
-
-    double ComputeAxialThickness(const OrthancVolumeImage& volume) const
-    {
-      double thickness;
-
-      size_t n = volume.GetSlicesCount();
-      if (n > 1)
-      {
-        const Slice& a = volume.GetSlice(0);
-        const Slice& b = volume.GetSlice(n - 1);
-        thickness = ((reference_.ProjectAlongNormal(b.GetGeometry().GetOrigin()) -
-                      reference_.ProjectAlongNormal(a.GetGeometry().GetOrigin())) /
-                     (static_cast<double>(n) - 1.0));
-      }
-      else
-      {
-        thickness = volume.GetSlice(0).GetThickness();
-      }
-
-      if (thickness <= 0)
-      {
-        // The slices should have been sorted with increasing Z
-        // (along the normal) by the OrthancSlicesLoader
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-      }
-      else
-      {
-        return thickness;
-      }
-    }
-
-    void SetupAxial(const OrthancVolumeImage& volume)
-    {
-      const Slice& axial = volume.GetSlice(0);
-
-      width_ = axial.GetWidth();
-      height_ = axial.GetHeight();
-      depth_ = volume.GetSlicesCount();
-
-      pixelSpacingX_ = axial.GetPixelSpacingX();
-      pixelSpacingY_ = axial.GetPixelSpacingY();
-      sliceThickness_ = ComputeAxialThickness(volume);
-
-      reference_ = axial.GetGeometry();
-    }
-
-    void SetupCoronal(const OrthancVolumeImage& volume)
-    {
-      const Slice& axial = volume.GetSlice(0);
-      double axialThickness = ComputeAxialThickness(volume);
-
-      width_ = axial.GetWidth();
-      height_ = static_cast<unsigned int>(volume.GetSlicesCount());
-      depth_ = axial.GetHeight();
-
-      pixelSpacingX_ = axial.GetPixelSpacingX();
-      pixelSpacingY_ = axialThickness;
-      sliceThickness_ = axial.GetPixelSpacingY();
-
-      OrthancStone::Vector origin = axial.GetGeometry().GetOrigin();
-      origin += (static_cast<double>(volume.GetSlicesCount() - 1) *
-                 axialThickness * axial.GetGeometry().GetNormal());
-
-      reference_ = OrthancStone::CoordinateSystem3D(origin,
-                                                    axial.GetGeometry().GetAxisX(),
-                                                    - axial.GetGeometry().GetNormal());
-    }
-
-    void SetupSagittal(const OrthancVolumeImage& volume)
-    {
-      const Slice& axial = volume.GetSlice(0);
-      double axialThickness = ComputeAxialThickness(volume);
-
-      width_ = axial.GetHeight();
-      height_ = static_cast<unsigned int>(volume.GetSlicesCount());
-      depth_ = axial.GetWidth();
-
-      pixelSpacingX_ = axial.GetPixelSpacingY();
-      pixelSpacingY_ = axialThickness;
-      sliceThickness_ = axial.GetPixelSpacingX();
-
-      OrthancStone::Vector origin = axial.GetGeometry().GetOrigin();
-      origin += (static_cast<double>(volume.GetSlicesCount() - 1) *
-                 axialThickness * axial.GetGeometry().GetNormal());
-
-      reference_ = OrthancStone::CoordinateSystem3D(origin,
-                                                    axial.GetGeometry().GetAxisY(),
-                                                    axial.GetGeometry().GetNormal());
-    }
-
-  public:
-    VolumeImageGeometry(const OrthancVolumeImage& volume,
-                        OrthancStone::VolumeProjection projection)
-    {
-      if (volume.GetSlicesCount() == 0)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-
-      converter_ = volume.GetSlice(0).GetConverter();
-
-      switch (projection)
-      {
-        case OrthancStone::VolumeProjection_Axial:
-          SetupAxial(volume);
-          break;
-
-        case OrthancStone::VolumeProjection_Coronal:
-          SetupCoronal(volume);
-          break;
-
-        case OrthancStone::VolumeProjection_Sagittal:
-          SetupSagittal(volume);
-          break;
-
-        default:
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-    }
-
-    size_t GetSlicesCount() const
-    {
-      return depth_;
-    }
-
-    const OrthancStone::Vector& GetNormal() const
-    {
-      return reference_.GetNormal();
-    }
-
-    bool LookupSlice(size_t& index,
-                     const OrthancStone::CoordinateSystem3D& slice) const
-    {
-      bool opposite;
-      if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite,
-                                                               reference_.GetNormal(),
-                                                               slice.GetNormal()))
-      {
-        return false;
-      }
-
-      double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) -
-                  reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_;
-
-      int s = static_cast<int>(boost::math::iround(z));
-
-      if (s < 0 ||
-          s >= static_cast<int>(depth_))
-      {
-        return false;
-      }
-      else
-      {
-        index = static_cast<size_t>(s);
-        return true;
-      }
-    }
-
-    Slice* GetSlice(size_t slice) const
-    {
-      if (slice >= depth_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
-      }
-      else
-      {
-        OrthancStone::CoordinateSystem3D origin(reference_.GetOrigin() +
-                                                static_cast<double>(slice) * sliceThickness_ * reference_.GetNormal(),
-                                                reference_.GetAxisX(),
-                                                reference_.GetAxisY());
-
-        return new Slice(origin, pixelSpacingX_, pixelSpacingY_, sliceThickness_,
-                         width_, height_, converter_);
-      }
-    }
-  };
-
-
-
-  class VolumeImageMPRSlicer :
-    public IVolumeSlicer,
-    public OrthancStone::IObserver
-  {
-  private:
-    class RendererFactory : public LayerReadyMessage::IRendererFactory
-    {
-    private:
-      const Orthanc::ImageAccessor&  frame_;
-      const Slice&                   slice_;
-      bool                           isFullQuality_;
-
-    public:
-      RendererFactory(const Orthanc::ImageAccessor& frame,
-                      const Slice& slice,
-                      bool isFullQuality) :
-        frame_(frame),
-        slice_(slice),
-        isFullQuality_(isFullQuality)
-      {
-      }
-
-      virtual ILayerRenderer* CreateRenderer() const
-      {
-        return FrameRenderer::CreateRenderer(frame_, slice_, isFullQuality_);
-      }
-    };
-
-
-    OrthancVolumeImage&                 volume_;
-    std::auto_ptr<VolumeImageGeometry>  axialGeometry_;
-    std::auto_ptr<VolumeImageGeometry>  coronalGeometry_;
-    std::auto_ptr<VolumeImageGeometry>  sagittalGeometry_;
-
-
-    bool IsGeometryReady() const
-    {
-      return axialGeometry_.get() != NULL;
-    }
-
-    void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message)
-    {
-      assert(&message.GetOrigin() == &volume_);
-
-      // These 3 values are only used to speed up the IVolumeSlicer
-      axialGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Axial));
-      coronalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Coronal));
-      sagittalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Sagittal));
-
-      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
-    }
-
-    void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message)
-    {
-      assert(&message.GetOrigin() == &volume_);
-
-      BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
-    }
-
-    void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message)
-    {
-      assert(&message.GetOrigin() == &volume_);
-
-      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
-    }
-
-    void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message)
-    {
-      assert(&message.GetOrigin() == &volume_);
-
-      //IVolumeSlicer::OnSliceContentChange(slice);
-
-      // TODO Improve this?
-      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
-    }
-
-    const VolumeImageGeometry& GetProjectionGeometry(OrthancStone::VolumeProjection projection)
-    {
-      if (!IsGeometryReady())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-
-      switch (projection)
-      {
-        case OrthancStone::VolumeProjection_Axial:
-          return *axialGeometry_;
-
-        case OrthancStone::VolumeProjection_Sagittal:
-          return *sagittalGeometry_;
-
-        case OrthancStone::VolumeProjection_Coronal:
-          return *coronalGeometry_;
-
-        default:
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
-      }
-    }
-
-
-    bool DetectProjection(OrthancStone::VolumeProjection& projection,
-                          const OrthancStone::CoordinateSystem3D& viewportSlice)
-    {
-      bool isOpposite;  // Ignored
-
-      if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                              viewportSlice.GetNormal(),
-                                                              axialGeometry_->GetNormal()))
-      {
-        projection = OrthancStone::VolumeProjection_Axial;
-        return true;
-      }
-      else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                                   viewportSlice.GetNormal(),
-                                                                   sagittalGeometry_->GetNormal()))
-      {
-        projection = OrthancStone::VolumeProjection_Sagittal;
-        return true;
-      }
-      else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite,
-                                                                   viewportSlice.GetNormal(),
-                                                                   coronalGeometry_->GetNormal()))
-      {
-        projection = OrthancStone::VolumeProjection_Coronal;
-        return true;
-      }
-      else
-      {
-        return false;
-      }
-    }
-
-
-  public:
-    VolumeImageMPRSlicer(OrthancStone::MessageBroker& broker,
-                         OrthancVolumeImage&  volume) :
-      IVolumeSlicer(broker),
-      IObserver(broker),
-      volume_(volume)
-    {
-      volume_.RegisterObserverCallback(
-        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage>
-        (*this, &VolumeImageMPRSlicer::OnGeometryReady));
-
-      volume_.RegisterObserverCallback(
-        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryErrorMessage>
-        (*this, &VolumeImageMPRSlicer::OnGeometryError));
-
-      volume_.RegisterObserverCallback(
-        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::ContentChangedMessage>
-        (*this, &VolumeImageMPRSlicer::OnContentChanged));
-
-      volume_.RegisterObserverCallback(
-        new OrthancStone::Callable<VolumeImageMPRSlicer, ISlicedVolume::SliceContentChangedMessage>
-        (*this, &VolumeImageMPRSlicer::OnSliceContentChanged));
-    }
-
-    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
-                           const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
-    {
-      OrthancStone::VolumeProjection projection;
-
-      if (!IsGeometryReady() ||
-          !DetectProjection(projection, viewportSlice))
-      {
-        return false;
-      }
-      else
-      {
-        // As the slices of the volumic image are arranged in a box,
-        // we only consider one single reference slice (the one with index 0).
-        std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0));
-        slice->GetExtent(points);
-
-        return true;
-      }
-    }
-
-    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE
-    {
-      OrthancStone::VolumeProjection projection;
-
-      if (IsGeometryReady() &&
-          DetectProjection(projection, viewportSlice))
-      {
-        const VolumeImageGeometry& geometry = GetProjectionGeometry(projection);
-
-        size_t closest;
-
-        if (geometry.LookupSlice(closest, viewportSlice))
-        {
-          bool isFullQuality = true;  // TODO
-
-          std::auto_ptr<Orthanc::Image> frame;
-
-          {
-            OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast<unsigned int>(closest));
-
-            // TODO Transfer ownership if non-axial, to avoid memcpy
-            frame.reset(Orthanc::Image::Clone(reader.GetAccessor()));
-          }
-
-          std::auto_ptr<Slice> slice(geometry.GetSlice(closest));
-
-          RendererFactory factory(*frame, *slice, isFullQuality);
-
-          BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice->GetGeometry()));
-          return;
-        }
-      }
-
-      // Error
-      OrthancStone::CoordinateSystem3D slice;
-      BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, slice));
-    }
-  };
-
-
-  class VolumeImageInteractor :
-    public IWorldSceneInteractor,
-    public OrthancStone::IObserver
-  {
-  private:
-    SliceViewerWidget&                  widget_;
-    OrthancStone::VolumeProjection      projection_;
-    std::auto_ptr<VolumeImageGeometry>  slices_;
-    size_t                              slice_;
-
-  protected:
-    void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message)
-    {
-      if (slices_.get() == NULL)
-      {
-        const OrthancVolumeImage& image =
-          dynamic_cast<const OrthancVolumeImage&>(message.GetOrigin());
-
-        slices_.reset(new VolumeImageGeometry(image, projection_));
-        SetSlice(slices_->GetSlicesCount() / 2);
-
-        widget_.FitContent();
-      }
-    }
-
-    virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget,
-                                                        const ViewportGeometry& view,
-                                                        OrthancStone::MouseButton button,
-                                                        OrthancStone::KeyboardModifiers modifiers,
-                                                        int viewportX,
-                                                        int viewportY,
-                                                        double x,
-                                                        double y,
-                                                        IStatusBar* statusBar,
-                                                        const std::vector<Touch>& touches) ORTHANC_OVERRIDE
-    {
-      return  NULL;
-    }
-
-    virtual void MouseOver(OrthancStone::CairoContext& context,
-                           WorldSceneWidget& widget,
-                           const ViewportGeometry& view,
-                           double x,
-                           double y,
-                           IStatusBar* statusBar) ORTHANC_OVERRIDE
-    {
-    }
-
-    virtual void MouseWheel(WorldSceneWidget& widget,
-                            OrthancStone::MouseWheelDirection direction,
-                            OrthancStone::KeyboardModifiers modifiers,
-                            IStatusBar* statusBar) ORTHANC_OVERRIDE
-    {
-      int scale = (modifiers & OrthancStone::KeyboardModifiers_Control ? 10 : 1);
-
-      switch (direction)
-      {
-        case OrthancStone::MouseWheelDirection_Up:
-          OffsetSlice(-scale);
-          break;
-
-        case OrthancStone::MouseWheelDirection_Down:
-          OffsetSlice(scale);
-          break;
-
-        default:
-          break;
-      }
-    }
-
-    virtual void KeyPressed(WorldSceneWidget& widget,
-                            OrthancStone::KeyboardKeys key,
-                            char keyChar,
-                            OrthancStone::KeyboardModifiers modifiers,
-                            IStatusBar* statusBar) ORTHANC_OVERRIDE
-    {
-      switch (keyChar)
-      {
-        case 's':
-          widget.FitContent();
-          break;
-
-        default:
-          break;
-      }
-    }
-
-  public:
-    VolumeImageInteractor(OrthancStone::MessageBroker& broker,
-                          OrthancVolumeImage& volume,
-                          SliceViewerWidget& widget,
-                          OrthancStone::VolumeProjection projection) :
-      IObserver(broker),
-      widget_(widget),
-      projection_(projection)
-    {
-      widget.SetInteractor(*this);
-
-      volume.RegisterObserverCallback(
-        new OrthancStone::Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage>
-        (*this, &VolumeImageInteractor::OnGeometryReady));
-    }
-
-    bool IsGeometryReady() const
-    {
-      return slices_.get() != NULL;
-    }
-
-    size_t GetSlicesCount() const
-    {
-      if (slices_.get() == NULL)
-      {
-        return 0;
-      }
-      else
-      {
-        return slices_->GetSlicesCount();
-      }
-    }
-
-    void OffsetSlice(int offset)
-    {
-      if (slices_.get() != NULL)
-      {
-        int slice = static_cast<int>(slice_) + offset;
-
-        if (slice < 0)
-        {
-          slice = 0;
-        }
-
-        if (slice >= static_cast<int>(slices_->GetSlicesCount()))
-        {
-          slice = static_cast<unsigned int>(slices_->GetSlicesCount()) - 1;
-        }
-
-        if (slice != static_cast<int>(slice_))
-        {
-          SetSlice(slice);
-        }
-      }
-    }
-
-    void SetSlice(size_t slice)
-    {
-      if (slices_.get() != NULL)
-      {
-        slice_ = slice;
-
-        std::auto_ptr<Slice> tmp(slices_->GetSlice(slice_));
-        widget_.SetSlice(tmp->GetGeometry());
-      }
-    }
-  };
-
-
-
-  class ReferenceLineSource : public IVolumeSlicer
-  {
-  private:
-    class RendererFactory : public LayerReadyMessage::IRendererFactory
-    {
-    private:
-      double                     x1_;
-      double                     y1_;
-      double                     x2_;
-      double                     y2_;
-      const OrthancStone::CoordinateSystem3D&  slice_;
-
-    public:
-      RendererFactory(double x1,
-                      double y1,
-                      double x2,
-                      double y2,
-                      const OrthancStone::CoordinateSystem3D& slice) :
-        x1_(x1),
-        y1_(y1),
-        x2_(x2),
-        y2_(y2),
-        slice_(slice)
-      {
-      }
-
-      virtual ILayerRenderer* CreateRenderer() const
-      {
-        return new LineLayerRenderer(x1_, y1_, x2_, y2_, slice_);
-      }
-    };
-
-    SliceViewerWidget&  otherPlane_;
-
-  public:
-    ReferenceLineSource(OrthancStone::MessageBroker& broker,
-                        SliceViewerWidget&  otherPlane) :
-      IVolumeSlicer(broker),
-      otherPlane_(otherPlane)
-    {
-      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
-    }
-
-    virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
-                           const OrthancStone::CoordinateSystem3D& viewportSlice)
-    {
-      return false;
-    }
-
-    virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
-    {
-      Slice reference(viewportSlice, 0.001);
-
-      OrthancStone::Vector p, d;
-
-      const OrthancStone::CoordinateSystem3D& slice = otherPlane_.GetSlice();
-
-      // Compute the line of intersection between the two slices
-      if (!OrthancStone::GeometryToolbox::IntersectTwoPlanes(p, d,
-                                                             slice.GetOrigin(), slice.GetNormal(),
-                                                             viewportSlice.GetOrigin(), viewportSlice.GetNormal()))
-      {
-        // The two slice are parallel, don't try and display the intersection
-        BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry()));
-      }
-      else
-      {
-        double x1, y1, x2, y2;
-        viewportSlice.ProjectPoint(x1, y1, p);
-        viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d);
-
-        const OrthancStone::Extent2D extent = otherPlane_.GetSceneExtent();
-
-        if (OrthancStone::GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2,
-                                                               x1, y1, x2, y2,
-                                                               extent.GetX1(), extent.GetY1(),
-                                                               extent.GetX2(), extent.GetY2()))
-        {
-          RendererFactory factory(x1, y1, x2, y2, slice);
-          BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, reference.GetGeometry()));
-        }
-        else
-        {
-          // Error: Parallel slices
-          BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry()));
-        }
-      }
-    }
-  };
-}
--- a/Platforms/Generic/DelayedCallCommand.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Generic/DelayedCallCommand.h	Tue May 21 14:27:35 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "IOracleCommand.h"
 
-#include "../../Framework/Toolbox/IDelayedCallExecutor.h"
+#include "../../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h"
 #include "../../Framework/Messages/IObservable.h"
 #include "../../Framework/Messages/ICallable.h"
 #include "../../Applications/Generic/NativeStoneApplicationContext.h"
--- a/Platforms/Generic/OracleDelayedCallExecutor.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Generic/OracleDelayedCallExecutor.h	Tue May 21 14:27:35 2019 +0200
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "../../Framework/Toolbox/IDelayedCallExecutor.h"
+#include "../../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h"
 #include "Oracle.h"
 #include "../../Applications/Generic/NativeStoneApplicationContext.h"
 #include "DelayedCallCommand.h"
--- a/Platforms/Generic/OracleWebService.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Generic/OracleWebService.cpp	Tue May 21 14:27:35 2019 +0200
@@ -20,7 +20,7 @@
 
 
 #include "OracleWebService.h"
-#include "../../Framework/Toolbox/IWebService.h"
+#include "../../Framework/Deprecated/Toolbox/IWebService.h"
 
 namespace Deprecated
 {
--- a/Platforms/Generic/OracleWebService.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Generic/OracleWebService.h	Tue May 21 14:27:35 2019 +0200
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "../../Framework/Toolbox/BaseWebService.h"
+#include "../../Framework/Deprecated/Toolbox/BaseWebService.h"
 #include "Oracle.h"
 #include "WebServiceGetCommand.h"
 #include "WebServicePostCommand.h"
--- a/Platforms/Generic/WebServiceCommandBase.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Generic/WebServiceCommandBase.h	Tue May 21 14:27:35 2019 +0200
@@ -23,7 +23,7 @@
 
 #include "IOracleCommand.h"
 
-#include "../../Framework/Toolbox/IWebService.h"
+#include "../../Framework/Deprecated/Toolbox/IWebService.h"
 #include "../../Framework/Messages/IObservable.h"
 #include "../../Framework/Messages/ICallable.h"
 #include "../../Applications/Generic/NativeStoneApplicationContext.h"
--- a/Platforms/Wasm/Defaults.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Wasm/Defaults.cpp	Tue May 21 14:27:35 2019 +0200
@@ -2,9 +2,8 @@
 
 #include "WasmWebService.h"
 #include "WasmDelayedCallExecutor.h"
-#include <Framework/dev.h>
-#include "Framework/Widgets/TestCairoWidget.h"
-#include <Framework/Viewport/WidgetViewport.h>
+#include "../../Framework/Deprecated/Widgets/TestCairoWidget.h"
+#include <Framework/Deprecated/Viewport/WidgetViewport.h>
 #include <Applications/Wasm/StartupParametersBuilder.h>
 #include <Platforms/Wasm/WasmPlatformApplicationAdapter.h>
 #include <Core/Logging.h>
--- a/Platforms/Wasm/Defaults.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Wasm/Defaults.h	Tue May 21 14:27:35 2019 +0200
@@ -2,9 +2,8 @@
 
 #include <emscripten/emscripten.h>
 
-#include <Framework/dev.h>
-#include <Framework/Viewport/WidgetViewport.h>
-#include <Framework/Widgets/LayoutWidget.h>
+#include "../../Framework/Deprecated/Viewport/WidgetViewport.h"
+#include "../../Framework/Deprecated/Widgets/LayoutWidget.h"
 #include <Applications/IStoneApplication.h>
 #include <Platforms/Wasm/WasmPlatformApplicationAdapter.h>
 
--- a/Platforms/Wasm/WasmDelayedCallExecutor.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Wasm/WasmDelayedCallExecutor.h	Tue May 21 14:27:35 2019 +0200
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <Framework/Toolbox/IDelayedCallExecutor.h>
+#include "../../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h"
 #include <Core/OrthancException.h>
 
 namespace Deprecated
--- a/Platforms/Wasm/WasmViewport.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Wasm/WasmViewport.h	Tue May 21 14:27:35 2019 +0200
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <Framework/Viewport/WidgetViewport.h>
+#include "../../Framework/Deprecated/Viewport/WidgetViewport.h"
 
 #include <emscripten/emscripten.h>
 
--- a/Platforms/Wasm/WasmWebService.h	Tue May 21 13:27:54 2019 +0200
+++ b/Platforms/Wasm/WasmWebService.h	Tue May 21 14:27:35 2019 +0200
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <Framework/Toolbox/BaseWebService.h>
+#include "../../Framework/Deprecated/Toolbox/BaseWebService.h"
 #include <Core/OrthancException.h>
 
 namespace Deprecated
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue May 21 13:27:54 2019 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Tue May 21 14:27:35 2019 +0200
@@ -305,7 +305,55 @@
     DEPENDS "${ORTHANC_STONE_ROOT}/Platforms/Wasm/default-library.js")
 endif()
 
+
+set(ORTHANC_STONE_DEPRECATED_SOURCES
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/CircleMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/ColorFrameRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/FrameRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/IVolumeSlicer.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/LineLayerRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/LineMeasureTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/RenderStyle.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/SliceOutlineRenderer.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/SmartLoader.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/BaseWebService.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/DicomFrameConverter.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/DownloadStack.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/IWebService.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancApiClient.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/Slice.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/ViewportGeometry.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IMouseTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IStatusBar.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IViewport.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/WidgetViewport.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Volumes/StructureSetLoader.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/CairoWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/EmptyWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/IWidget.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/IWorldSceneInteractor.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/IWorldSceneMouseTracker.h
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/LayoutWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/PanMouseTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/PanZoomMouseTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/SliceViewerWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/TestCairoWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/TestWorldSceneWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/WidgetBase.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/WorldSceneWidget.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/ZoomMouseTracker.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Deprecated/dev.h
+  )
+
+
 list(APPEND ORTHANC_STONE_SOURCES
+  ${ORTHANC_STONE_DEPRECATED_SOURCES}
+  
   #${ORTHANC_STONE_ROOT}/Framework/Layers/SeriesFrameRendererFactory.cpp
   #${ORTHANC_STONE_ROOT}/Framework/Layers/SingleFrameRendererFactory.cpp
 
@@ -362,24 +410,13 @@
   ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/PointerTypes.h
   ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/ViewportController.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/ViewportController.h
-
+  
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/FontRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/Glyph.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphAlphabet.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphBitmapAlphabet.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphTextureAlphabet.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Fonts/TextBoundingBox.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/CircleMeasureTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/ColorFrameRenderer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomSeriesVolumeSlicer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomStructureSetSlicer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/FrameRenderer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/GrayscaleFrameRenderer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/IVolumeSlicer.h
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/LineLayerRenderer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/RenderStyle.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Layers/SliceOutlineRenderer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Loaders/BasicFetchingItemsSorter.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Loaders/BasicFetchingStrategy.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyAlphaLayer.cpp
@@ -398,61 +435,31 @@
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyTextLayer.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyWidget.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyWindowingTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/SmartLoader.cpp
   ${ORTHANC_STONE_ROOT}/Framework/StoneEnumerations.cpp
   ${ORTHANC_STONE_ROOT}/Framework/StoneException.h
   ${ORTHANC_STONE_ROOT}/Framework/StoneInitialization.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/AffineTransform2D.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/BaseWebService.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/CoordinateSystem3D.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DicomFrameConverter.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DicomStructureSet.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DownloadStack.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DynamicBitmap.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Extent2D.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/FiniteProjectiveCamera.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/IDelayedCallExecutor.h
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/IWebService.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/MessagingToolbox.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/OrientedBoundingBox.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/OrthancApiClient.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/OrthancSlicesLoader.cpp
+
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlices.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlicesCursor.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Slice.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ViewportGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/VolumeImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoContext.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoSurface.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Viewport/IMouseTracker.h
-  ${ORTHANC_STONE_ROOT}/Framework/Viewport/IStatusBar.h
-  ${ORTHANC_STONE_ROOT}/Framework/Viewport/IViewport.h
-  ${ORTHANC_STONE_ROOT}/Framework/Viewport/WidgetViewport.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/ImageBuffer3D.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Volumes/StructureSetLoader.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeReslicer.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/CairoWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/EmptyWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWidget.h
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneInteractor.h
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneMouseTracker.h
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/LayoutWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/PanMouseTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/PanZoomMouseTracker.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/SliceViewerWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/TestCairoWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/TestWorldSceneWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/WidgetBase.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/WorldSceneWidget.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Widgets/ZoomMouseTracker.cpp
-
-  ${ORTHANC_STONE_ROOT}/Framework/dev.h
 
   ${ORTHANC_STONE_ROOT}/Framework/Messages/ICallable.h
   ${ORTHANC_STONE_ROOT}/Framework/Messages/IMessage.h
--- a/Samples/WebAssembly/BasicScene.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/Samples/WebAssembly/BasicScene.cpp	Tue May 21 14:27:35 2019 +0200
@@ -153,10 +153,8 @@
     void SetupEvents(const std::string& canvas);
 
   public:
-    WebAssemblyViewport(MessageBroker& broker,
-                        const std::string& canvas) :
+    WebAssemblyViewport(const std::string& canvas) :
       context_(canvas),
-      scene_(broker),
       compositor_(context_, scene_)
     {
       compositor_.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, 
@@ -363,7 +361,6 @@
 std::auto_ptr<OrthancStone::WebAssemblyViewport>  viewport1_;
 std::auto_ptr<OrthancStone::WebAssemblyViewport>  viewport2_;
 std::auto_ptr<OrthancStone::WebAssemblyViewport>  viewport3_;
-OrthancStone::MessageBroker  broker_;
 
 
 EM_BOOL OnWindowResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
@@ -399,15 +396,15 @@
   EMSCRIPTEN_KEEPALIVE
   void Initialize()
   {
-    viewport1_.reset(new OrthancStone::WebAssemblyViewport(broker_, "mycanvas1"));
+    viewport1_.reset(new OrthancStone::WebAssemblyViewport("mycanvas1"));
     PrepareScene(viewport1_->GetScene());
     viewport1_->UpdateSize();
 
-    viewport2_.reset(new OrthancStone::WebAssemblyViewport(broker_, "mycanvas2"));
+    viewport2_.reset(new OrthancStone::WebAssemblyViewport("mycanvas2"));
     PrepareScene(viewport2_->GetScene());
     viewport2_->UpdateSize();
 
-    viewport3_.reset(new OrthancStone::WebAssemblyViewport(broker_, "mycanvas3"));
+    viewport3_.reset(new OrthancStone::WebAssemblyViewport("mycanvas3"));
     PrepareScene(viewport3_->GetScene());
     viewport3_->UpdateSize();
 
--- a/UnitTestsSources/UnitTestsMain.cpp	Tue May 21 13:27:54 2019 +0200
+++ b/UnitTestsSources/UnitTestsMain.cpp	Tue May 21 14:27:35 2019 +0200
@@ -19,14 +19,14 @@
  **/
 
 
-#include "../Framework/dev.h"
 #include "gtest/gtest.h"
 
-#include "../Framework/Layers/FrameRenderer.h"
-#include "../Framework/Toolbox/DownloadStack.h"
+#include "../Framework/Deprecated/Layers/FrameRenderer.h"
+#include "../Framework/Deprecated/Toolbox/DownloadStack.h"
+#include "../Framework/Deprecated/Toolbox/OrthancSlicesLoader.h"
 #include "../Framework/Toolbox/FiniteProjectiveCamera.h"
+#include "../Framework/Toolbox/GeometryToolbox.h"
 #include "../Framework/Toolbox/MessagingToolbox.h"
-#include "../Framework/Toolbox/OrthancSlicesLoader.h"
 #include "../Framework/Volumes/ImageBuffer3D.h"
 #include "../Platforms/Generic/OracleWebService.h"
 
@@ -42,97 +42,6 @@
 #include <boost/math/special_functions/round.hpp>
 
 
-#if 0
-namespace OrthancStone
-{
-  class Tata : public OrthancSlicesLoader::ICallback
-  {
-  public:
-    virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader)
-    {
-      printf(">> %d\n", (int) loader.GetSliceCount());
-
-      for (size_t i = 0; i < loader.GetSliceCount(); i++)
-      {
-        const_cast<OrthancSlicesLoader&>(loader).ScheduleLoadSliceImage(i, SliceImageQuality_FullPng);
-      }
-    }
-
-    virtual void NotifyGeometryError(const OrthancSlicesLoader& loader)
-    {
-      printf("Error\n");
-    }
-
-    virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader,
-                                       unsigned int sliceIndex,
-                                       const Slice& slice,
-                                       std::auto_ptr<Orthanc::ImageAccessor>& image,
-                                       SliceImageQuality quality)
-    {
-      std::auto_ptr<Orthanc::ImageAccessor> tmp(image);
-      printf("Slice OK %dx%d\n", tmp->GetWidth(), tmp->GetHeight());
-    }
-
-    virtual void NotifySliceImageError(const OrthancSlicesLoader& loader,
-                                       unsigned int sliceIndex,
-                                       const Slice& slice,
-                                       SliceImageQuality quality)
-    {
-      printf("ERROR 2\n");
-    }
-  };
-}
-
-
-TEST(Toto, DISABLED_Tutu)
-{
-  OrthancStone::Oracle oracle(4);
-  oracle.Start();
-
-  Orthanc::WebServiceParameters web;
-  //OrthancStone::OrthancAsynchronousWebService orthanc(web, 4);
-  OrthancStone::OracleWebService orthanc(oracle, web);
-  //orthanc.Start();
-
-  OrthancStone::Tata tata;
-  OrthancStone::OrthancSlicesLoader loader(tata, orthanc);
-  loader.ScheduleLoadSeries("c1c4cb95-05e3bd11-8da9f5bb-87278f71-0b2b43f5");
-  //loader.ScheduleLoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5");
-
-  //loader.ScheduleLoadInstance("19816330-cb02e1cf-df3a8fe8-bf510623-ccefe9f5", 0);
-
-  /*printf(">> %d\n", loader.GetSliceCount());
-    loader.ScheduleLoadSliceImage(31);*/
-
-  boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
-
-  //orthanc.Stop();
-  oracle.Stop();
-}
-
-
-TEST(Toto, Tata)
-{
-  OrthancStone::Oracle oracle(4);
-  oracle.Start();
-
-  Orthanc::WebServiceParameters web;
-  OrthancStone::OracleWebService orthanc(oracle, web);
-  OrthancStone::OrthancVolumeImage volume(orthanc, true);
-
-  //volume.ScheduleLoadInstance("19816330-cb02e1cf-df3a8fe8-bf510623-ccefe9f5", 0);
-  //volume.ScheduleLoadSeries("318603c5-03e8cffc-a82b6ee1-3ccd3c1e-18d7e3bb"); // COMUNIX PET
-  //volume.ScheduleLoadSeries("7124dba7-09803f33-98b73826-33f14632-ea842d29"); // COMUNIX CT
-  //volume.ScheduleLoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // Delphine sagital
-  volume.ScheduleLoadSeries("6f1b492a-e181e200-44e51840-ef8db55e-af529ab6"); // Delphine ax 2.5
-
-  boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
-
-  oracle.Stop();
-}
-#endif
-
-
 TEST(GeometryToolbox, Interpolation)
 {
   using namespace OrthancStone::GeometryToolbox;