changeset 1305:a5326ce4f24b broker

Trackers and measuring tools now use the viewport instead of ViewportController, so that proper locks can be used
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 04 Mar 2020 09:45:38 +0100
parents b7fa67bf87fa
children fef1ec42a7db
files Framework/Scene2D/Internals/FixedPointAligner.cpp Framework/Scene2D/Internals/FixedPointAligner.h Framework/Scene2D/PanSceneTracker.cpp Framework/Scene2D/PanSceneTracker.h Framework/Scene2D/RotateSceneTracker.cpp Framework/Scene2D/RotateSceneTracker.h Framework/Scene2D/ZoomSceneTracker.cpp Framework/Scene2D/ZoomSceneTracker.h Framework/Scene2DViewport/AngleMeasureTool.cpp Framework/Scene2DViewport/AngleMeasureTool.h Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp Framework/Scene2DViewport/CreateAngleMeasureCommand.h Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp Framework/Scene2DViewport/CreateAngleMeasureTracker.h Framework/Scene2DViewport/CreateLineMeasureCommand.cpp Framework/Scene2DViewport/CreateLineMeasureCommand.h Framework/Scene2DViewport/CreateLineMeasureTracker.cpp Framework/Scene2DViewport/CreateLineMeasureTracker.h Framework/Scene2DViewport/EditAngleMeasureCommand.cpp Framework/Scene2DViewport/EditAngleMeasureCommand.h Framework/Scene2DViewport/EditAngleMeasureTracker.cpp Framework/Scene2DViewport/EditAngleMeasureTracker.h Framework/Scene2DViewport/EditLineMeasureCommand.cpp Framework/Scene2DViewport/EditLineMeasureCommand.h Framework/Scene2DViewport/EditLineMeasureTracker.cpp Framework/Scene2DViewport/EditLineMeasureTracker.h Framework/Scene2DViewport/LayerHolder.cpp Framework/Scene2DViewport/LayerHolder.h Framework/Scene2DViewport/LineMeasureTool.cpp Framework/Scene2DViewport/LineMeasureTool.h Framework/Scene2DViewport/MeasureCommands.cpp Framework/Scene2DViewport/MeasureCommands.h Framework/Scene2DViewport/MeasureTool.cpp Framework/Scene2DViewport/MeasureTool.h Framework/Scene2DViewport/MeasureTrackers.cpp Framework/Scene2DViewport/MeasureTrackers.h Framework/Scene2DViewport/OneGesturePointerTracker.cpp Framework/Scene2DViewport/OneGesturePointerTracker.h
diffstat 38 files changed, 497 insertions(+), 468 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Scene2D/Internals/FixedPointAligner.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/Internals/FixedPointAligner.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -25,26 +25,28 @@
 {
   namespace Internals
   {
-    FixedPointAligner::FixedPointAligner(boost::weak_ptr<ViewportController> controllerW,
+    FixedPointAligner::FixedPointAligner(IViewport& viewport,
                                          const ScenePoint2D& p) 
-      : controllerW_(controllerW)
+      : viewport_(viewport)
       , canvas_(p)
     {
-      boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-      pivot_ = canvas_.Apply(controller->GetCanvasToSceneTransform());
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      pivot_ = canvas_.Apply(lock->GetController().GetCanvasToSceneTransform());
     }
 
     
     void FixedPointAligner::Apply()
     {
-      boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-      ScenePoint2D p = canvas_.Apply(controller->GetCanvasToSceneTransform());
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      ScenePoint2D p = canvas_.Apply(
+        lock->GetController().GetCanvasToSceneTransform());
 
-      controller->SetSceneToCanvasTransform(
+      lock->GetController().SetSceneToCanvasTransform(
         AffineTransform2D::Combine(
-          controller->GetSceneToCanvasTransform(),
+          lock->GetController().GetSceneToCanvasTransform(),
           AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
                                           p.GetY() - pivot_.GetY())));
+      lock->Invalidate();
     }
   }
 }
--- a/Framework/Scene2D/Internals/FixedPointAligner.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/Internals/FixedPointAligner.h	Wed Mar 04 09:45:38 2020 +0100
@@ -22,6 +22,9 @@
 
 #include "../../Scene2DViewport/PredeclaredTypes.h"
 #include "../../Scene2D/ScenePoint2D.h"
+#include "../../Viewport/IViewport.h"
+
+#include <boost/weak_ptr.hpp>
 
 namespace OrthancStone
 {
@@ -32,12 +35,12 @@
     class FixedPointAligner : public boost::noncopyable
     {
     private:
-      boost::weak_ptr<ViewportController> controllerW_;
+      IViewport& viewport_;
       ScenePoint2D           pivot_;
       ScenePoint2D           canvas_;
 
     public:
-      FixedPointAligner(boost::weak_ptr<ViewportController> controllerW,
+      FixedPointAligner(IViewport& viewport,
                         const ScenePoint2D& p);
 
       void Apply();
--- a/Framework/Scene2D/PanSceneTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/PanSceneTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -20,16 +20,23 @@
 
 
 #include "PanSceneTracker.h"
+#include "../Viewport/IViewport.h"
 #include "../Scene2DViewport/ViewportController.h"
 
+#include <memory>
+
 namespace OrthancStone
 {
-  PanSceneTracker::PanSceneTracker(boost::weak_ptr<ViewportController> controllerW,
+  PanSceneTracker::PanSceneTracker(IViewport& viewport,
                                    const PointerEvent& event)
-    : OneGesturePointerTracker(controllerW)
-    , originalSceneToCanvas_(GetController()->GetSceneToCanvasTransform())
-    , originalCanvasToScene_(GetController()->GetCanvasToSceneTransform())
+    : OneGesturePointerTracker(viewport)
   {
+    
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+
+    originalSceneToCanvas_ = lock->GetController().GetSceneToCanvasTransform();
+    originalCanvasToScene_ = lock->GetController().GetCanvasToSceneTransform();
+
     pivot_ = event.GetMainPosition().Apply(originalCanvasToScene_);
   }
 
@@ -38,25 +45,19 @@
   {
     ScenePoint2D p = event.GetMainPosition().Apply(originalCanvasToScene_);
 
-      // The controller is a weak pointer. It could be deleted when the
-      // tracker is still alive (for instance, because of a lost WebGL
-      // context)
-      if(GetController().get() != NULL)
-      {
-      GetController()->SetSceneToCanvasTransform(
-        AffineTransform2D::Combine(
-          originalSceneToCanvas_,
-          AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
-                                          p.GetY() - pivot_.GetY())));
-      }
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+
+    lock->GetController().SetSceneToCanvasTransform(
+      AffineTransform2D::Combine(
+        originalSceneToCanvas_,
+        AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
+                                        p.GetY() - pivot_.GetY())));
+    lock->Invalidate();
   }
 
   void PanSceneTracker::Cancel()
   {
-      if(GetController().get() != NULL)
-      {
-        GetController()->SetSceneToCanvasTransform(originalSceneToCanvas_);
-      }
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    lock->GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
   }
-
 }
--- a/Framework/Scene2D/PanSceneTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/PanSceneTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -28,14 +28,13 @@
   class PanSceneTracker : public OneGesturePointerTracker
   {
   public:
-    PanSceneTracker(boost::weak_ptr<ViewportController> controllerW,
+    PanSceneTracker(IViewport& viewport,
                     const PointerEvent& event);
 
     virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
     virtual void Cancel() ORTHANC_OVERRIDE;
 
   private:
-    boost::weak_ptr<ViewportController> controllerW_;
     ScenePoint2D           pivot_;
     AffineTransform2D      originalSceneToCanvas_;
     AffineTransform2D      originalCanvasToScene_;
--- a/Framework/Scene2D/RotateSceneTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/RotateSceneTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -13,7 +13,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Affero General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
@@ -23,23 +23,25 @@
 
 namespace OrthancStone
 {
-  RotateSceneTracker::RotateSceneTracker(boost::weak_ptr<ViewportController> controllerW,
+  RotateSceneTracker::RotateSceneTracker(IViewport& viewport,
                                          const PointerEvent& event)
-    : OneGesturePointerTracker(controllerW)
+    : OneGesturePointerTracker(viewport)
     , click_(event.GetMainPosition())
-    , aligner_(controllerW, click_)
+    , aligner_(viewport, click_)
     , isFirst_(true)
-    , originalSceneToCanvas_(GetController()->GetSceneToCanvasTransform())
   {
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    originalSceneToCanvas_ = lock->GetController().GetSceneToCanvasTransform();
+
   }
-  
+
   void RotateSceneTracker::PointerMove(const PointerEvent& event)
   {
     ScenePoint2D p = event.GetMainPosition();
     double dx = p.GetX() - click_.GetX();
     double dy = p.GetY() - click_.GetY();
 
-    if (std::abs(dx) > 5.0 || 
+    if (std::abs(dx) > 5.0 ||
         std::abs(dy) > 5.0)
     {
       double a = atan2(dy, dx);
@@ -50,28 +52,22 @@
         isFirst_ = false;
       }
 
-      // The controller is a weak pointer. It could be deleted when the
-      // tracker is still alive (for instance, because of a lost WebGL
-      // context that triggers a recreation of the viewport)
-      if(GetController().get() != NULL)
-      {
-        GetController()->SetSceneToCanvasTransform(
-          AffineTransform2D::Combine(
-            AffineTransform2D::CreateRotation(a - referenceAngle_),
-            originalSceneToCanvas_));
-        
-        aligner_.Apply();
-      }
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+
+      lock->GetController().SetSceneToCanvasTransform(
+        AffineTransform2D::Combine(
+          AffineTransform2D::CreateRotation(a - referenceAngle_),
+          originalSceneToCanvas_));
+      aligner_.Apply();
+      lock->Invalidate();
     }
   }
 
   void RotateSceneTracker::Cancel()
   {
-      // See remark above
-      if(GetController().get() != NULL)
-      {
-        GetController()->SetSceneToCanvasTransform(originalSceneToCanvas_);
-      }
+    // See remark above
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    lock->GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
+    lock->Invalidate();
   }
-
 }
--- a/Framework/Scene2D/RotateSceneTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/RotateSceneTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -30,7 +30,7 @@
   class RotateSceneTracker : public OneGesturePointerTracker
   {
   public:
-    RotateSceneTracker(boost::weak_ptr<ViewportController> controllerW,
+    RotateSceneTracker(IViewport& viewport,
                        const PointerEvent& event);
 
     virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
--- a/Framework/Scene2D/ZoomSceneTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/ZoomSceneTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -22,19 +22,19 @@
 #include "ZoomSceneTracker.h"
 #include "../Scene2DViewport/ViewportController.h"
 
-using boost::weak_ptr;
-using boost::shared_ptr;
-
 namespace OrthancStone
 {
-  ZoomSceneTracker::ZoomSceneTracker(weak_ptr<ViewportController> controllerW,
+  ZoomSceneTracker::ZoomSceneTracker(IViewport& viewport,
                                      const PointerEvent& event,
                                      unsigned int canvasHeight)
-    : OneGesturePointerTracker(controllerW)
+    : OneGesturePointerTracker(viewport)
     , clickY_(event.GetMainPosition().GetY())
-    , aligner_(controllerW, event.GetMainPosition())
-    , originalSceneToCanvas_(GetController()->GetSceneToCanvasTransform())
+    , aligner_(viewport, event.GetMainPosition())
   {
+    
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    originalSceneToCanvas_ = lock->GetController().GetSceneToCanvasTransform();
+
     if (canvasHeight <= 3)
     {
       active_ = false;
@@ -76,26 +76,20 @@
 
       double zoom = pow(2.0, z);
 
-      // The controller is a weak pointer. It could be deleted when the
-      // tracker is still alive (for instance, because of a lost WebGL
-      // context)
-      if(GetController().get() != NULL)
-      {
-        GetController()->SetSceneToCanvasTransform(
-          AffineTransform2D::Combine(
-            AffineTransform2D::CreateScaling(zoom, zoom),
-            originalSceneToCanvas_));
-
-        aligner_.Apply();
-      }
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      lock->GetController().SetSceneToCanvasTransform(
+        AffineTransform2D::Combine(
+          AffineTransform2D::CreateScaling(zoom, zoom),
+          originalSceneToCanvas_));
+      aligner_.Apply();
+      lock->Invalidate();
     }
   }
 
   void ZoomSceneTracker::Cancel()
   {
-      if(GetController().get() != NULL)
-      {
-        GetController()->SetSceneToCanvasTransform(originalSceneToCanvas_);
-      }
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    lock->GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
+    lock->Invalidate();
   }
 }
--- a/Framework/Scene2D/ZoomSceneTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2D/ZoomSceneTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -23,14 +23,17 @@
 
 
 #include "../Scene2DViewport/OneGesturePointerTracker.h"
+#include "../Viewport/IViewport.h"
 #include "Internals/FixedPointAligner.h"
 
+#include <boost/weak_ptr.hpp>
+
 namespace OrthancStone
 {
   class ZoomSceneTracker : public OneGesturePointerTracker
   {
   public:
-    ZoomSceneTracker(boost::weak_ptr<ViewportController> controllerW,
+    ZoomSceneTracker(IViewport& viewport,
                      const PointerEvent& event,
                      unsigned int canvasHeight);
 
--- a/Framework/Scene2DViewport/AngleMeasureTool.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -42,12 +42,12 @@
   // the params in the LayerHolder ctor specify the number of polyline and text
   // layers
   AngleMeasureTool::AngleMeasureTool(
-    boost::weak_ptr<ViewportController> controllerW)
-    : MeasureTool(controllerW)
+    IViewport& viewport)
+    : MeasureTool(viewport)
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
-    , layerHolder_(boost::make_shared<LayerHolder>(controllerW,1,5))
+    , layerHolder_(boost::make_shared<LayerHolder>(viewport,1,5))
 #else
-    , layerHolder_(boost::make_shared<LayerHolder>(controllerW, 1, 1))
+    , layerHolder_(boost::make_shared<LayerHolder>(viewport, 1, 1))
 #endif
     , angleHighlightArea_(AngleHighlightArea_None)
   {
@@ -108,7 +108,9 @@
   
   void AngleMeasureTool::SetMemento(boost::shared_ptr<MeasureToolMemento> mementoBase)
   {
-    boost::shared_ptr<AngleMeasureToolMemento> memento = boost::dynamic_pointer_cast<AngleMeasureToolMemento>(mementoBase);
+    boost::shared_ptr<AngleMeasureToolMemento> memento = 
+      boost::dynamic_pointer_cast<AngleMeasureToolMemento>(mementoBase);
+
     ORTHANC_ASSERT(memento.get() != NULL, "Internal error: wrong (or bad) memento");
     center_   = memento->center_;
     side1End_ = memento->side1End_;
@@ -119,7 +121,8 @@
   std::string AngleMeasureTool::GetDescription()
   {
     std::stringstream ss;
-    ss << "AngleMeasureTool. Center = " << center_ << " Side1End = " << side1End_ << " Side2End = " << side2End_;
+    ss << "AngleMeasureTool. Center = " << center_ << " Side1End = " 
+       << side1End_ << " Side2End = " << side2End_;
     return ss.str();
   }
 
@@ -131,36 +134,51 @@
 
   AngleMeasureTool::AngleHighlightArea AngleMeasureTool::AngleHitTest(ScenePoint2D p) const
   {
-    const double pixelToScene = GetController()->GetScene().GetCanvasToSceneTransform().ComputeZoom();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
 
-    const double SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD = pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD * pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD;
+    const double pixelToScene = scene.GetCanvasToSceneTransform().ComputeZoom();
+
+    const double SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD = 
+      pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD * 
+      pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD;
 
     {
-      const double sqDistanceFromSide1End = ScenePoint2D::SquaredDistancePtPt(p, side1End_);
+      const double sqDistanceFromSide1End = 
+        ScenePoint2D::SquaredDistancePtPt(p, side1End_);
+
       if (sqDistanceFromSide1End <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
         return AngleHighlightArea_Side1End;
     }
 
     {
-      const double sqDistanceFromSide2End = ScenePoint2D::SquaredDistancePtPt(p, side2End_);
+      const double sqDistanceFromSide2End = 
+        ScenePoint2D::SquaredDistancePtPt(p, side2End_);
+
       if (sqDistanceFromSide2End <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
         return AngleHighlightArea_Side2End;
     }
 
     {
-      const double sqDistanceFromCenter = ScenePoint2D::SquaredDistancePtPt(p, center_);
+      const double sqDistanceFromCenter = 
+        ScenePoint2D::SquaredDistancePtPt(p, center_);
       if (sqDistanceFromCenter <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
         return AngleHighlightArea_Center;
     }
 
     {
-      const double sqDistanceFromSide1 = ScenePoint2D::SquaredDistancePtSegment(center_, side1End_, p);
+      const double sqDistanceFromSide1 = 
+        ScenePoint2D::SquaredDistancePtSegment(center_, side1End_, p);
+
       if (sqDistanceFromSide1 <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
         return AngleHighlightArea_Side1;
     }
 
     {
-      const double sqDistanceFromSide2 = ScenePoint2D::SquaredDistancePtSegment(center_, side2End_, p);
+      const double sqDistanceFromSide2 = 
+        ScenePoint2D::SquaredDistancePtSegment(center_, side2End_, p);
+
       if (sqDistanceFromSide2 <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
         return AngleHighlightArea_Side2;
     }
@@ -168,7 +186,7 @@
     return AngleHighlightArea_None;
   }
 
-  bool AngleMeasureTool::HitTest(ScenePoint2D p) const
+  bool AngleMeasureTool::HitTest(ScenePoint2D p)
   {
     return AngleHitTest(p) != AngleHighlightArea_None;
   }
@@ -176,8 +194,12 @@
 
   boost::shared_ptr<IFlexiblePointerTracker> AngleMeasureTool::CreateEditionTracker(const PointerEvent& e)
   {
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
+
     ScenePoint2D scenePos = e.GetMainPosition().Apply(
-      GetController()->GetScene().GetCanvasToSceneTransform());
+      scene.GetCanvasToSceneTransform());
 
     if (!HitTest(scenePos))
       return boost::shared_ptr<IFlexiblePointerTracker>();
@@ -186,12 +208,12 @@
       new EditLineMeasureTracker(
         boost::shared_ptr<LineMeasureTool> measureTool;
         MessageBroker & broker,
-        boost::weak_ptr<ViewportController>          controllerW,
+        IViewport&          viewport,
         const PointerEvent & e);
     */
 
     boost::shared_ptr<EditAngleMeasureTracker> editAngleMeasureTracker(
-      new EditAngleMeasureTracker(shared_from_this(), GetController(), e));
+      new EditAngleMeasureTracker(shared_from_this(), viewport_, e));
     return editAngleMeasureTracker;
   }
 
@@ -205,7 +227,10 @@
   {
     if (IsSceneAlive())
     {
-      boost::shared_ptr<ViewportController> controller = GetController();
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      ViewportController& controller = lock->GetController();
+      Scene2D& scene = controller.GetScene();
+
       if (IsEnabled())
       {
         layerHolder_->CreateLayersIfNeeded();
@@ -217,8 +242,13 @@
           {
             polylineLayer->ClearAllChains();
 
-            const Color color(TOOL_ANGLE_LINES_COLOR_RED, TOOL_ANGLE_LINES_COLOR_GREEN, TOOL_ANGLE_LINES_COLOR_BLUE);
-            const Color highlightColor(TOOL_ANGLE_LINES_HL_COLOR_RED, TOOL_ANGLE_LINES_HL_COLOR_GREEN, TOOL_ANGLE_LINES_HL_COLOR_BLUE);
+            const Color color(TOOL_ANGLE_LINES_COLOR_RED, 
+                              TOOL_ANGLE_LINES_COLOR_GREEN, 
+                              TOOL_ANGLE_LINES_COLOR_BLUE);
+
+            const Color highlightColor(TOOL_ANGLE_LINES_HL_COLOR_RED, 
+                                       TOOL_ANGLE_LINES_HL_COLOR_GREEN, 
+                                       TOOL_ANGLE_LINES_HL_COLOR_BLUE);
 
             // sides
             {
@@ -227,19 +257,29 @@
                 chain.push_back(side1End_);
                 chain.push_back(center_);
 
-                if ((angleHighlightArea_ == AngleHighlightArea_Side1) || (angleHighlightArea_ == AngleHighlightArea_Side2))
+                if ((angleHighlightArea_ == AngleHighlightArea_Side1) ||
+                    (angleHighlightArea_ == AngleHighlightArea_Side2))
+                {
                   polylineLayer->AddChain(chain, false, highlightColor);
+                } 
                 else
+                {
                   polylineLayer->AddChain(chain, false, color);
+                }
               }
               {
                 PolylineSceneLayer::Chain chain;
                 chain.push_back(side2End_);
                 chain.push_back(center_);
-                if ((angleHighlightArea_ == AngleHighlightArea_Side1) || (angleHighlightArea_ == AngleHighlightArea_Side2))
+                if ((angleHighlightArea_ == AngleHighlightArea_Side1) ||
+                  (angleHighlightArea_ == AngleHighlightArea_Side2))
+                {
                   polylineLayer->AddChain(chain, false, highlightColor);
+                }
                 else
+                {
                   polylineLayer->AddChain(chain, false, color);
+                }
               }
             }
 
@@ -248,8 +288,8 @@
               {
                 PolylineSceneLayer::Chain chain;
                 //TODO: take DPI into account
-                AddSquare(chain, controller->GetScene(), side1End_, 
-                          GetController()->GetHandleSideLengthS());
+                AddSquare(chain, controller.GetScene(), side1End_, 
+                          controller.GetHandleSideLengthS());
               
                 if (angleHighlightArea_ == AngleHighlightArea_Side1End)
                   polylineLayer->AddChain(chain, true, highlightColor);
@@ -260,8 +300,8 @@
               {
                 PolylineSceneLayer::Chain chain;
                 //TODO: take DPI into account
-                AddSquare(chain, controller->GetScene(), side2End_, 
-                          GetController()->GetHandleSideLengthS());
+                AddSquare(chain, controller.GetScene(), side2End_, 
+                          controller.GetHandleSideLengthS());
 
                 if (angleHighlightArea_ == AngleHighlightArea_Side2End)
                   polylineLayer->AddChain(chain, true, highlightColor);
@@ -275,7 +315,7 @@
               PolylineSceneLayer::Chain chain;
 
               AddShortestArc(chain, side1End_, center_, side2End_,
-                             controller->GetAngleToolArcRadiusS());
+                             controller.GetAngleToolArcRadiusS());
               if (angleHighlightArea_ == AngleHighlightArea_Center)
                 polylineLayer->AddChain(chain, false, highlightColor);
               else
@@ -297,8 +337,8 @@
           double delta = NormalizeAngle(p2cAngle - p1cAngle);
           double theta = p1cAngle + delta / 2;
 
-          double ox = controller->GetAngleTopTextLabelDistanceS() * cos(theta);
-          double oy = controller->GetAngleTopTextLabelDistanceS() * sin(theta);
+          double ox = controller.GetAngleTopTextLabelDistanceS() * cos(theta);
+          double oy = controller.GetAngleTopTextLabelDistanceS() * sin(theta);
 
           double pointX = center_.GetX() + ox;
           double pointY = center_.GetY() + oy;
@@ -311,10 +351,10 @@
 
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
           SetTextLayerOutlineProperties(
-            controller->GetScene(), layerHolder_, buf, ScenePoint2D(pointX, pointY), 0);
+            scene, layerHolder_, buf, ScenePoint2D(pointX, pointY), 0);
 #else
           SetTextLayerProperties(
-            controller->GetScene(), layerHolder_, buf, ScenePoint2D(pointX, pointY) , 0);
+            scene, layerHolder_, buf, ScenePoint2D(pointX, pointY) , 0);
 #endif
 
 #if 0
@@ -374,6 +414,7 @@
       {
         RemoveFromScene();
       }
+      lock->Invalidate();
     }
   }
 }
--- a/Framework/Scene2DViewport/AngleMeasureTool.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/AngleMeasureTool.h	Wed Mar 04 09:45:38 2020 +0100
@@ -40,7 +40,7 @@
   class AngleMeasureTool : public MeasureTool
   {
   public:
-    AngleMeasureTool(boost::weak_ptr<ViewportController> controllerW);
+    AngleMeasureTool(IViewport& viewport);
 
     ~AngleMeasureTool();
 
@@ -48,7 +48,7 @@
     void SetCenter(ScenePoint2D start);
     void SetSide2End(ScenePoint2D start);
 
-    virtual bool HitTest(ScenePoint2D p) const ORTHANC_OVERRIDE;
+    virtual bool HitTest(ScenePoint2D p) ORTHANC_OVERRIDE;
     virtual void Highlight(ScenePoint2D p) ORTHANC_OVERRIDE;
     virtual void ResetHighlightState() ORTHANC_OVERRIDE;
     virtual boost::shared_ptr<IFlexiblePointerTracker> CreateEditionTracker(const PointerEvent& e) ORTHANC_OVERRIDE;
--- a/Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -26,13 +26,17 @@
 namespace OrthancStone
 {
   CreateAngleMeasureCommand::CreateAngleMeasureCommand(
-    boost::weak_ptr<ViewportController> controllerW,
+    IViewport& viewport,
     ScenePoint2D           point)
-    : CreateMeasureCommand(controllerW)
+    : CreateMeasureCommand(viewport)
     , measureTool_(
-      boost::make_shared<AngleMeasureTool>(controllerW))
+      boost::make_shared<AngleMeasureTool>(viewport))
   {
-    GetController()->AddMeasureTool(measureTool_);
+    
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+
+    controller.AddMeasureTool(measureTool_);
     measureTool_->SetSide1End(point);
     measureTool_->SetCenter(point);
     measureTool_->SetSide2End(point);
--- a/Framework/Scene2DViewport/CreateAngleMeasureCommand.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateAngleMeasureCommand.h	Wed Mar 04 09:45:38 2020 +0100
@@ -28,7 +28,7 @@
   public:
     /** Ctor sets end of side 1*/
     CreateAngleMeasureCommand(
-      boost::weak_ptr<ViewportController> controllerW,
+      IViewport& viewport,
       ScenePoint2D           point);
 
     /** This method sets center*/
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -26,22 +26,18 @@
 namespace OrthancStone
 {
   CreateAngleMeasureTracker::CreateAngleMeasureTracker(
-    boost::weak_ptr<ViewportController>          controllerW,
-    const PointerEvent&             e)
-    : CreateMeasureTracker(controllerW)
+    IViewport& viewport,
+    const PointerEvent& e)
+    : CreateMeasureTracker(viewport)
     , state_(CreatingSide1)
   {
     ScenePoint2D point = e.GetMainPosition();
-    
-    {
-      boost::shared_ptr<ViewportController> controller = controllerW.lock();
-      if (controller)
-      {
-        point = e.GetMainPosition().Apply(controller->GetScene().GetCanvasToSceneTransform());
-      }
+    {    
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      Scene2D& scene = lock->GetController().GetScene();
+      point = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
     }
-    
-    command_.reset(new CreateAngleMeasureCommand(controllerW, point));
+    command_.reset(new CreateAngleMeasureCommand(viewport, point));
   }
 
   CreateAngleMeasureTracker::~CreateAngleMeasureTracker()
@@ -57,11 +53,13 @@
         "PointerMove: active_ == false");
     }
 
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (controller)
+    
     {
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      ViewportController& controller = lock->GetController();
+
       ScenePoint2D scenePos = event.GetMainPosition().Apply(
-        controller->GetScene().GetCanvasToSceneTransform());
+        controller.GetScene().GetCanvasToSceneTransform());
 
       switch (state_)
       {
@@ -78,6 +76,7 @@
       }
       //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
       //  "scenePos.GetY() = " << scenePos.GetY();
+      lock->Invalidate();
     }
   }
 
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -38,7 +38,7 @@
     must be supplied, too
     */
     CreateAngleMeasureTracker(
-      boost::weak_ptr<ViewportController>          controllerW,
+      IViewport&          viewport,
       const PointerEvent&             e);
 
     ~CreateAngleMeasureTracker();
--- a/Framework/Scene2DViewport/CreateLineMeasureCommand.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateLineMeasureCommand.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -26,14 +26,18 @@
 namespace OrthancStone
 {
   CreateLineMeasureCommand::CreateLineMeasureCommand(
-    boost::weak_ptr<ViewportController> controllerW,
+    IViewport& viewport,
     ScenePoint2D           point)
-    : CreateMeasureCommand(controllerW)
+    : CreateMeasureCommand(viewport)
     , measureTool_(
-      boost::make_shared<LineMeasureTool>(controllerW))
+      boost::make_shared<LineMeasureTool>(viewport))
   {
-    GetController()->AddMeasureTool(measureTool_);
+    
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    controller.AddMeasureTool(measureTool_);
     measureTool_->Set(point, point);
+    lock->Invalidate();
   }
 
   void CreateLineMeasureCommand::SetEnd(ScenePoint2D scenePos)
--- a/Framework/Scene2DViewport/CreateLineMeasureCommand.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateLineMeasureCommand.h	Wed Mar 04 09:45:38 2020 +0100
@@ -27,7 +27,7 @@
   {
   public:
     CreateLineMeasureCommand(
-      boost::weak_ptr<ViewportController> controllerW,
+      IViewport& viewport,
       ScenePoint2D           point);
 
     // the starting position is set in the ctor
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -26,21 +26,17 @@
 namespace OrthancStone
 {
   CreateLineMeasureTracker::CreateLineMeasureTracker(
-    boost::weak_ptr<ViewportController>          controllerW,
+    IViewport&          viewport,
     const PointerEvent&             e)
-    : CreateMeasureTracker(controllerW)
+    : CreateMeasureTracker(viewport)
   {
     ScenePoint2D point = e.GetMainPosition();
-    
     {
-      boost::shared_ptr<ViewportController> controller = controllerW.lock();
-      if (controller)
-      {
-        point = e.GetMainPosition().Apply(controller->GetScene().GetCanvasToSceneTransform());
-      }
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      ViewportController& controller = lock->GetController();
+      point = e.GetMainPosition().Apply(controller.GetScene().GetCanvasToSceneTransform());
     }
-
-    command_.reset(new CreateLineMeasureCommand(controllerW, point));
+    command_.reset(new CreateLineMeasureCommand(viewport, point));
   }
 
   CreateLineMeasureTracker::~CreateLineMeasureTracker()
@@ -57,20 +53,19 @@
         "PointerMove: active_ == false");
     }
 
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (controller)
-    {
-      ScenePoint2D scenePos = event.GetMainPosition().Apply(
-        controller->GetScene().GetCanvasToSceneTransform());
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+
+    ScenePoint2D scenePos = event.GetMainPosition().Apply(
+      controller.GetScene().GetCanvasToSceneTransform());
       
-      //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
-      //  "scenePos.GetY() = " << scenePos.GetY();
+    //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << "     " <<
+    //  "scenePos.GetY() = " << scenePos.GetY();
       
-      CreateLineMeasureTracker* concreteThis =
-        dynamic_cast<CreateLineMeasureTracker*>(this);
-      assert(concreteThis != NULL);
-      GetCommand()->SetEnd(scenePos);
-    }
+    CreateLineMeasureTracker* concreteThis =
+      dynamic_cast<CreateLineMeasureTracker*>(this);
+    assert(concreteThis != NULL);
+    GetCommand()->SetEnd(scenePos);
   }
 
   void CreateLineMeasureTracker::PointerUp(const PointerEvent& e)
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -38,7 +38,7 @@
     must be supplied, too
     */
     CreateLineMeasureTracker(
-      boost::weak_ptr<ViewportController>          controllerW,
+      IViewport&          viewport,
       const PointerEvent&             e);
 
     ~CreateLineMeasureTracker();
--- a/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -24,8 +24,8 @@
 {
   EditAngleMeasureCommand::EditAngleMeasureCommand(
     boost::shared_ptr<MeasureTool>  measureTool,
-    boost::weak_ptr<ViewportController> controllerW)
-    : EditMeasureCommand(measureTool, controllerW)
+    IViewport& viewport)
+    : EditMeasureCommand(measureTool, viewport)
     , measureTool_(measureTool)
   {
   }
--- a/Framework/Scene2DViewport/EditAngleMeasureCommand.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditAngleMeasureCommand.h	Wed Mar 04 09:45:38 2020 +0100
@@ -29,7 +29,7 @@
     /** Ctor sets end of side 1*/
     EditAngleMeasureCommand(
       boost::shared_ptr<MeasureTool>  measureTool,
-      boost::weak_ptr<ViewportController> controllerW);
+      IViewport& viewport);
 
     /** This method sets center*/
     void SetCenter(ScenePoint2D scenePos);
--- a/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -27,21 +27,18 @@
 {
   EditAngleMeasureTracker::EditAngleMeasureTracker(
     boost::shared_ptr<MeasureTool>  measureTool,
-    boost::weak_ptr<ViewportController> controllerW,
+    IViewport& viewport,
     const PointerEvent& e)
-    : EditMeasureTracker(controllerW, e)
+    : EditMeasureTracker(viewport, e)
   {
     ScenePoint2D scenePos = e.GetMainPosition();
-
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (controller)
     {
-      scenePos = e.GetMainPosition().Apply(controller->GetScene().GetCanvasToSceneTransform());
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      ViewportController& controller = lock->GetController();
+      scenePos = e.GetMainPosition().Apply(controller.GetScene().GetCanvasToSceneTransform());
     }
-
     modifiedZone_ = dynamic_cast<AngleMeasureTool&>(*measureTool).AngleHitTest(scenePos);
-
-    command_.reset(new EditAngleMeasureCommand(measureTool, controllerW));
+    command_.reset(new EditAngleMeasureCommand(measureTool, viewport));
   }
 
   EditAngleMeasureTracker::~EditAngleMeasureTracker()
@@ -51,54 +48,54 @@
 
   void EditAngleMeasureTracker::PointerMove(const PointerEvent& e)
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (controller)
-    {
-      ScenePoint2D scenePos = e.GetMainPosition().Apply(
-        controller->GetScene().GetCanvasToSceneTransform());
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
+
+    ScenePoint2D scenePos = e.GetMainPosition().Apply(
+      scene.GetCanvasToSceneTransform());
 
-      ScenePoint2D delta = scenePos - GetOriginalClickPosition();
+    ScenePoint2D delta = scenePos - GetOriginalClickPosition();
+
+    boost::shared_ptr<AngleMeasureToolMemento> memento =
+      boost::dynamic_pointer_cast<AngleMeasureToolMemento>(command_->mementoOriginal_);
+
+    ORTHANC_ASSERT(memento.get() != NULL);
 
-      boost::shared_ptr<AngleMeasureToolMemento> memento =
-        boost::dynamic_pointer_cast<AngleMeasureToolMemento>(command_->mementoOriginal_);
-
-      ORTHANC_ASSERT(memento.get() != NULL);
-
-      switch (modifiedZone_)
+    switch (modifiedZone_)
+    {
+      case AngleMeasureTool::AngleHighlightArea_Center:
+      {
+        ScenePoint2D newCenter = memento->center_ + delta;
+        GetCommand()->SetCenter(newCenter);
+      }
+      break;
+      case AngleMeasureTool::AngleHighlightArea_Side1:
+      case AngleMeasureTool::AngleHighlightArea_Side2:
       {
-        case AngleMeasureTool::AngleHighlightArea_Center:
-        {
-          ScenePoint2D newCenter = memento->center_ + delta;
-          GetCommand()->SetCenter(newCenter);
-        }
+        ScenePoint2D newCenter = memento->center_ + delta;
+        ScenePoint2D newSide1End = memento->side1End_ + delta;
+        ScenePoint2D newSide2End = memento->side2End_ + delta;
+        GetCommand()->SetCenter(newCenter);
+        GetCommand()->SetSide1End(newSide1End);
+        GetCommand()->SetSide2End(newSide2End);
+      }
+      break;
+      case AngleMeasureTool::AngleHighlightArea_Side1End:
+      {
+        ScenePoint2D newSide1End = memento->side1End_ + delta;
+        GetCommand()->SetSide1End(newSide1End);
+      }
+      break;
+      case AngleMeasureTool::AngleHighlightArea_Side2End:
+      {
+        ScenePoint2D newSide2End = memento->side2End_ + delta;
+        GetCommand()->SetSide2End(newSide2End);
+      }
+      break;
+      default:
+        LOG(WARNING) << "Warning: please retry the measuring tool editing operation!";
         break;
-        case AngleMeasureTool::AngleHighlightArea_Side1:
-        case AngleMeasureTool::AngleHighlightArea_Side2:
-        {
-          ScenePoint2D newCenter = memento->center_ + delta;
-          ScenePoint2D newSide1End = memento->side1End_ + delta;
-          ScenePoint2D newSide2End = memento->side2End_ + delta;
-          GetCommand()->SetCenter(newCenter);
-          GetCommand()->SetSide1End(newSide1End);
-          GetCommand()->SetSide2End(newSide2End);
-        }
-        break;
-        case AngleMeasureTool::AngleHighlightArea_Side1End:
-        {
-          ScenePoint2D newSide1End = memento->side1End_ + delta;
-          GetCommand()->SetSide1End(newSide1End);
-        }
-        break;
-        case AngleMeasureTool::AngleHighlightArea_Side2End:
-        {
-          ScenePoint2D newSide2End = memento->side2End_ + delta;
-          GetCommand()->SetSide2End(newSide2End);
-        }
-        break;
-        default:
-          LOG(WARNING) << "Warning: please retry the measuring tool editing operation!";
-          break;
-      }
     }
   }
 
@@ -119,5 +116,4 @@
     ORTHANC_ASSERT(ret.get() != NULL, "Internal error in EditAngleMeasureTracker::GetCommand()");
     return ret;
   }
-
 }
--- a/Framework/Scene2DViewport/EditAngleMeasureTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -38,7 +38,7 @@
     */
     EditAngleMeasureTracker(
       boost::shared_ptr<MeasureTool>  measureTool,
-      boost::weak_ptr<ViewportController> controllerW,
+      IViewport& viewport,
       const PointerEvent& e);
 
     ~EditAngleMeasureTracker();
--- a/Framework/Scene2DViewport/EditLineMeasureCommand.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditLineMeasureCommand.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -24,8 +24,8 @@
 {
   EditLineMeasureCommand::EditLineMeasureCommand(
     boost::shared_ptr<MeasureTool>  measureTool,
-    boost::weak_ptr<ViewportController> controllerW)
-    : EditMeasureCommand(measureTool, controllerW)
+    IViewport& viewport)
+    : EditMeasureCommand(measureTool, viewport)
     , measureTool_(measureTool)
   {
   }
--- a/Framework/Scene2DViewport/EditLineMeasureCommand.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditLineMeasureCommand.h	Wed Mar 04 09:45:38 2020 +0100
@@ -28,7 +28,7 @@
   public:
     EditLineMeasureCommand(
       boost::shared_ptr<MeasureTool>  measureTool,
-      boost::weak_ptr<ViewportController> controllerW);
+      IViewport& viewport);
 
     void SetStart(ScenePoint2D scenePos);
     void SetEnd(ScenePoint2D scenePos);
--- a/Framework/Scene2DViewport/EditLineMeasureTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditLineMeasureTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -28,23 +28,18 @@
 {
   EditLineMeasureTracker::EditLineMeasureTracker(
     boost::shared_ptr<MeasureTool>  measureTool,
-    boost::weak_ptr<ViewportController> controllerW,
-    const PointerEvent& e) 
-    : EditMeasureTracker(controllerW, e)
+    IViewport& viewport,
+    const PointerEvent& e)
+    : EditMeasureTracker(viewport, e)
   {
     ScenePoint2D scenePos = e.GetMainPosition();
-
     {
-      boost::shared_ptr<ViewportController> controller = controllerW.lock();
-      if (controller)
-      {
-        scenePos = e.GetMainPosition().Apply(controller->GetScene().GetCanvasToSceneTransform());
-      }
+      std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+      Scene2D& scene = lock->GetController().GetScene();
+      scenePos = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
     }
-
     modifiedZone_ = dynamic_cast<LineMeasureTool&>(*measureTool).LineHitTest(scenePos);
-
-    command_.reset(new EditLineMeasureCommand(measureTool, controllerW));
+    command_.reset(new EditLineMeasureCommand(measureTool, viewport));
   }
 
   EditLineMeasureTracker::~EditLineMeasureTracker()
@@ -54,48 +49,48 @@
 
   void EditLineMeasureTracker::PointerMove(const PointerEvent& e)
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (controller)
-    {
-      ScenePoint2D scenePos = e.GetMainPosition().Apply(
-        controller->GetScene().GetCanvasToSceneTransform());
-      
-      ScenePoint2D delta = scenePos - GetOriginalClickPosition();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
+
+    ScenePoint2D scenePos = e.GetMainPosition().Apply(
+      scene.GetCanvasToSceneTransform());
 
-      boost::shared_ptr<LineMeasureToolMemento> memento =
-        boost::dynamic_pointer_cast<LineMeasureToolMemento>(command_->mementoOriginal_);
+    ScenePoint2D delta = scenePos - GetOriginalClickPosition();
 
-      ORTHANC_ASSERT(memento.get() != NULL);
+    boost::shared_ptr<LineMeasureToolMemento> memento =
+      boost::dynamic_pointer_cast<LineMeasureToolMemento>(command_->mementoOriginal_);
+
+    ORTHANC_ASSERT(memento.get() != NULL);
 
-      switch (modifiedZone_)
-      {
-        case LineMeasureTool::LineHighlightArea_Start:
-        {
-          ScenePoint2D newStart = memento->start_ + delta;
-          GetCommand()->SetStart(newStart);
-        }
-        break;
-        case LineMeasureTool::LineHighlightArea_End:
-        {
-          ScenePoint2D newEnd = memento->end_ + delta;
-          GetCommand()->SetEnd(newEnd);
-        }
-        break;
-        case LineMeasureTool::LineHighlightArea_Segment:
-        {
-          ScenePoint2D newStart = memento->start_ + delta;
-          ScenePoint2D newEnd = memento->end_ + delta;
-          GetCommand()->SetStart(newStart);
-          GetCommand()->SetEnd(newEnd);
-        }
-        break;
-        default:
-          LOG(WARNING) << "Warning: please retry the measuring tool editing operation!";
-          break;
-      }
+    switch (modifiedZone_)
+    {
+    case LineMeasureTool::LineHighlightArea_Start:
+    {
+      ScenePoint2D newStart = memento->start_ + delta;
+      GetCommand()->SetStart(newStart);
+    }
+    break;
+    case LineMeasureTool::LineHighlightArea_End:
+    {
+      ScenePoint2D newEnd = memento->end_ + delta;
+      GetCommand()->SetEnd(newEnd);
+    }
+    break;
+    case LineMeasureTool::LineHighlightArea_Segment:
+    {
+      ScenePoint2D newStart = memento->start_ + delta;
+      ScenePoint2D newEnd = memento->end_ + delta;
+      GetCommand()->SetStart(newStart);
+      GetCommand()->SetEnd(newEnd);
+    }
+    break;
+    default:
+      LOG(WARNING) << "Warning: please retry the measuring tool editing operation!";
+      break;
     }
   }
-  
+
   void EditLineMeasureTracker::PointerUp(const PointerEvent& e)
   {
     alive_ = false;
--- a/Framework/Scene2DViewport/EditLineMeasureTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/EditLineMeasureTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -38,7 +38,7 @@
     */
     EditLineMeasureTracker(
       boost::shared_ptr<MeasureTool>  measureTool,
-      boost::weak_ptr<ViewportController> controllerW,
+      IViewport& viewport,
       const PointerEvent&                 e);
 
     ~EditLineMeasureTracker();
--- a/Framework/Scene2DViewport/LayerHolder.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/LayerHolder.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -22,20 +22,20 @@
 #include "../Scene2D/TextSceneLayer.h"
 #include "../Scene2D/PolylineSceneLayer.h"
 #include "../Scene2D/Scene2D.h"
-#include "../Scene2DViewport/ViewportController.h"
+#include "../Viewport/IViewport.h"
 #include "../StoneException.h"
 
 namespace OrthancStone
 {
   LayerHolder::LayerHolder(
-    boost::weak_ptr<ViewportController> controllerW,
-    int                    polylineLayerCount,
-    int                    textLayerCount,
-    int                    infoTextCount)
+    IViewport& viewport,
+    int        polylineLayerCount,
+    int        textLayerCount,
+    int        infoTextCount)
     : textLayerCount_(textLayerCount)
     , polylineLayerCount_(polylineLayerCount)
     , infoTextCount_(infoTextCount)
-    , controllerW_(controllerW)
+    , viewport_(viewport)
     , baseLayerIndex_(-1)
   {
 
@@ -43,28 +43,26 @@
 
   void LayerHolder::CreateLayers()
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
 
-    if (controller)
-    {
-      assert(baseLayerIndex_ == -1);
+    assert(baseLayerIndex_ == -1);
 
-      baseLayerIndex_ = controller->GetScene().GetMaxDepth() + 100;
+    baseLayerIndex_ = lock->GetController().GetScene().GetMaxDepth() + 100;
 
-      for (int i = 0; i < polylineLayerCount_; ++i)
-      {
-        std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
-        controller->GetScene().SetLayer(baseLayerIndex_ + i, layer.release());
-      }
+    for (int i = 0; i < polylineLayerCount_; ++i)
+    {
+      std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer());
+      lock->GetController().GetScene().SetLayer(baseLayerIndex_ + i, layer.release());
+    }
 
-      for (int i = 0; i < textLayerCount_; ++i)
-      {
-        std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
-        controller->GetScene().SetLayer(
-          baseLayerIndex_ + polylineLayerCount_ + i,
-          layer.release());
-      }
+    for (int i = 0; i < textLayerCount_; ++i)
+    {
+      std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer());
+      lock->GetController().GetScene().SetLayer(
+        baseLayerIndex_ + polylineLayerCount_ + i,
+        layer.release());
     }
+    lock->Invalidate();
   }
 
   void LayerHolder::CreateLayersIfNeeded()
@@ -86,65 +84,50 @@
   
   void LayerHolder::DeleteLayers()
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    Scene2D& scene = lock->GetController().GetScene();
 
-    if (controller)
+    for (int i = 0; i < textLayerCount_ + polylineLayerCount_; ++i)
     {
-      for (int i = 0; i < textLayerCount_ + polylineLayerCount_; ++i)
-      {
-        ORTHANC_ASSERT(controller->GetScene().HasLayer(baseLayerIndex_ + i), "No layer");
-        controller->GetScene().DeleteLayer(baseLayerIndex_ + i);
-      }
-      baseLayerIndex_ = -1;
+      ORTHANC_ASSERT(scene.HasLayer(baseLayerIndex_ + i), "No layer");
+      scene.DeleteLayer(baseLayerIndex_ + i);
     }
+    baseLayerIndex_ = -1;
+    lock->Invalidate();
   }
   
   PolylineSceneLayer* LayerHolder::GetPolylineLayer(int index /*= 0*/)
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    Scene2D& scene = lock->GetController().GetScene();
 
-    if (controller)
-    {
-      using namespace Orthanc;
-      ORTHANC_ASSERT(baseLayerIndex_ != -1);
-      ORTHANC_ASSERT(controller->GetScene().HasLayer(GetPolylineLayerIndex(index)));
-      ISceneLayer* layer =
-        &(controller->GetScene().GetLayer(GetPolylineLayerIndex(index)));
+    using namespace Orthanc;
+    ORTHANC_ASSERT(baseLayerIndex_ != -1);
+    ORTHANC_ASSERT(scene.HasLayer(GetPolylineLayerIndex(index)));
+    ISceneLayer* layer = &(scene.GetLayer(GetPolylineLayerIndex(index)));
       
-      PolylineSceneLayer* concreteLayer =
-        dynamic_cast<PolylineSceneLayer*>(layer);
+    PolylineSceneLayer* concreteLayer =
+      dynamic_cast<PolylineSceneLayer*>(layer);
       
-      ORTHANC_ASSERT(concreteLayer != NULL);
-      return concreteLayer;
-    }
-    else
-    {
-      return NULL; // TODO
-    }
+    ORTHANC_ASSERT(concreteLayer != NULL);
+    return concreteLayer;
   }
 
   TextSceneLayer* LayerHolder::GetTextLayer(int index /*= 0*/)
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    Scene2D& scene = lock->GetController().GetScene();
 
-    if (controller)
-    {
-      using namespace Orthanc;
-      ORTHANC_ASSERT(baseLayerIndex_ != -1);
-      ORTHANC_ASSERT(controller->GetScene().HasLayer(GetTextLayerIndex(index)));
-      ISceneLayer* layer =
-        &(controller->GetScene().GetLayer(GetTextLayerIndex(index)));
+    using namespace Orthanc;
+    ORTHANC_ASSERT(baseLayerIndex_ != -1);
+    ORTHANC_ASSERT(scene.HasLayer(GetTextLayerIndex(index)));
+    ISceneLayer* layer = &(scene.GetLayer(GetTextLayerIndex(index)));
       
-      TextSceneLayer* concreteLayer =
-        dynamic_cast<TextSceneLayer*>(layer);
+    TextSceneLayer* concreteLayer =
+      dynamic_cast<TextSceneLayer*>(layer);
       
-      ORTHANC_ASSERT(concreteLayer != NULL);
-      return concreteLayer;
-    }
-    else
-    {
-      return NULL; // TODO
-    }
+    ORTHANC_ASSERT(concreteLayer != NULL);
+    return concreteLayer;
   }
 
   int LayerHolder::GetPolylineLayerIndex(int index /*= 0*/)
@@ -153,8 +136,7 @@
     ORTHANC_ASSERT(index < polylineLayerCount_);
     return baseLayerIndex_ + index;
   }
-
-
+  
   int LayerHolder::GetTextLayerIndex(int index /*= 0*/)
   {
     using namespace Orthanc;
--- a/Framework/Scene2DViewport/LayerHolder.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/LayerHolder.h	Wed Mar 04 09:45:38 2020 +0100
@@ -43,7 +43,7 @@
     performed at this time
     */
     LayerHolder(
-      boost::weak_ptr<ViewportController> controllerW,
+      IViewport& viewport,
       int polylineLayerCount, int textLayerCount, int infoTextCount = 0);
 
     /**
@@ -101,7 +101,7 @@
     int textLayerCount_;
     int polylineLayerCount_;
     int infoTextCount_;
-    boost::weak_ptr<ViewportController> controllerW_;
+    IViewport& viewport_;
     int baseLayerIndex_;
   };
 }
--- a/Framework/Scene2DViewport/LineMeasureTool.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/LineMeasureTool.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -32,12 +32,12 @@
 {
 
   LineMeasureTool::LineMeasureTool(
-    boost::weak_ptr<ViewportController> controllerW)
-    : MeasureTool(controllerW)
+    IViewport& viewport)
+    : MeasureTool(viewport)
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
-    , layerHolder_(boost::make_shared<LayerHolder>(controllerW, 1, 5))
+    , layerHolder_(boost::make_shared<LayerHolder>(viewport, 1, 5))
 #else
-    , layerHolder_(boost::make_shared<LayerHolder>(controllerW, 1, 1))
+    , layerHolder_(boost::make_shared<LayerHolder>(viewport, 1, 1))
 #endif
     , lineHighlightArea_(LineHighlightArea_None)
   {
@@ -106,36 +106,50 @@
     SetLineHighlightArea(lineHighlightArea);
   }
 
-  LineMeasureTool::LineHighlightArea LineMeasureTool::LineHitTest(ScenePoint2D p) const
+  LineMeasureTool::LineHighlightArea LineMeasureTool::LineHitTest(ScenePoint2D p)
   {
-    const double pixelToScene =
-      GetController()->GetScene().GetCanvasToSceneTransform().ComputeZoom();
-    const double SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD = pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD * pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD;
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
 
-    const double sqDistanceFromStart = ScenePoint2D::SquaredDistancePtPt(p, start_);
+    const double pixelToScene = scene.GetCanvasToSceneTransform().ComputeZoom();
+    const double SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD = 
+      pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD * 
+      pixelToScene * HIT_TEST_MAX_DISTANCE_CANVAS_COORD;
+
+    const double sqDistanceFromStart = 
+      ScenePoint2D::SquaredDistancePtPt(p, start_);
+    
     if (sqDistanceFromStart <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
       return LineHighlightArea_Start;
     
     const double sqDistanceFromEnd = ScenePoint2D::SquaredDistancePtPt(p, end_);
+
     if (sqDistanceFromEnd <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
       return LineHighlightArea_End;
 
-    const double sqDistanceFromPtSegment = ScenePoint2D::SquaredDistancePtSegment(start_, end_, p);
+    const double sqDistanceFromPtSegment = 
+      ScenePoint2D::SquaredDistancePtSegment(start_, end_, p);
+    
     if (sqDistanceFromPtSegment <= SQUARED_HIT_TEST_MAX_DISTANCE_SCENE_COORD)
       return LineHighlightArea_Segment;
 
     return LineHighlightArea_None;
   }
 
-  bool LineMeasureTool::HitTest(ScenePoint2D p) const
+  bool LineMeasureTool::HitTest(ScenePoint2D p)
   {
     return LineHitTest(p) != LineHighlightArea_None;
   }
 
   boost::shared_ptr<IFlexiblePointerTracker> LineMeasureTool::CreateEditionTracker(const PointerEvent& e)
   {
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+    Scene2D& scene = controller.GetScene();
+
     ScenePoint2D scenePos = e.GetMainPosition().Apply(
-      GetController()->GetScene().GetCanvasToSceneTransform());
+      scene.GetCanvasToSceneTransform());
 
     if (!HitTest(scenePos))
       return boost::shared_ptr<IFlexiblePointerTracker>();
@@ -144,15 +158,14 @@
       new EditLineMeasureTracker(
         boost::shared_ptr<LineMeasureTool> measureTool;
         MessageBroker & broker,
-        boost::weak_ptr<ViewportController>          controllerW,
+        IViewport&          viewport,
         const PointerEvent & e);
     */
     boost::shared_ptr<EditLineMeasureTracker> editLineMeasureTracker(
-      new EditLineMeasureTracker(shared_from_this(), GetController(), e));
+      new EditLineMeasureTracker(shared_from_this(), viewport_, e));
     return editLineMeasureTracker;
   }
 
-
   boost::shared_ptr<MeasureToolMemento> LineMeasureTool::GetMemento() const
   {
     boost::shared_ptr<LineMeasureToolMemento> memento(new LineMeasureToolMemento());
@@ -161,10 +174,14 @@
     return memento;
   }
 
-  void LineMeasureTool::SetMemento(boost::shared_ptr<MeasureToolMemento> mementoBase)
+  void LineMeasureTool::SetMemento(
+    boost::shared_ptr<MeasureToolMemento> mementoBase)
   {
-    boost::shared_ptr<LineMeasureToolMemento> memento = boost::dynamic_pointer_cast<LineMeasureToolMemento>(mementoBase);
+    boost::shared_ptr<LineMeasureToolMemento> memento = 
+      boost::dynamic_pointer_cast<LineMeasureToolMemento>(mementoBase);
+    
     ORTHANC_ASSERT(memento.get() != NULL, "Internal error: wrong (or bad) memento");
+    
     start_ = memento->start_;
     end_ = memento->end_;
     RefreshScene();
@@ -176,8 +193,12 @@
     {
       if (IsEnabled())
       {
+        
+        std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+        ViewportController& controller = lock->GetController();
+        Scene2D& scene = controller.GetScene();
+
         layerHolder_->CreateLayersIfNeeded();
-
         {
           // Fill the polyline layer with the measurement line
 
@@ -210,8 +231,8 @@
                 PolylineSceneLayer::Chain chain;
               
                 //TODO: take DPI into account
-                AddSquare(chain, GetController()->GetScene(), start_, 
-                          GetController()->GetHandleSideLengthS());
+                AddSquare(chain, controller.GetScene(), start_, 
+                          controller.GetHandleSideLengthS());
               
                 if (lineHighlightArea_ == LineHighlightArea_Start)
                   polylineLayer->AddChain(chain, true, highlightColor);
@@ -223,8 +244,8 @@
                 PolylineSceneLayer::Chain chain;
               
                 //TODO: take DPI into account
-                AddSquare(chain, GetController()->GetScene(), end_, 
-                          GetController()->GetHandleSideLengthS());
+                AddSquare(chain, controller.GetScene(), end_, 
+                          controller.GetHandleSideLengthS());
               
                 if (lineHighlightArea_ == LineHighlightArea_End)
                   polylineLayer->AddChain(chain, true, highlightColor);
@@ -248,14 +269,19 @@
           double midX = 0.5 * (end_.GetX() + start_.GetX());
           double midY = 0.5 * (end_.GetY() + start_.GetY());
 
+          {
+
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
-          SetTextLayerOutlineProperties(
-            GetController()->GetScene(), layerHolder_, buf, ScenePoint2D(midX, midY), 0);
+            SetTextLayerOutlineProperties(
+              scene, layerHolder_, buf, ScenePoint2D(midX, midY), 0);
 #else
-          SetTextLayerProperties(
-            GetController()->GetScene(), layerHolder_, buf, ScenePoint2D(midX, midY), 0);
+            SetTextLayerProperties(
+              scene, layerHolder_, buf, ScenePoint2D(midX, midY), 0);
 #endif
+            lock->Invalidate();
+          }
         }
+        lock->Invalidate();
       }
       else
       {
--- a/Framework/Scene2DViewport/LineMeasureTool.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/LineMeasureTool.h	Wed Mar 04 09:45:38 2020 +0100
@@ -38,7 +38,7 @@
   class LineMeasureTool : public MeasureTool
   {
   public:
-    LineMeasureTool(boost::weak_ptr<ViewportController> controllerW);
+    LineMeasureTool(IViewport& viewport);
 
     ~LineMeasureTool();
 
@@ -47,7 +47,7 @@
     void Set(ScenePoint2D start, ScenePoint2D end);
 
 
-    virtual bool HitTest(ScenePoint2D p) const ORTHANC_OVERRIDE;
+    virtual bool HitTest(ScenePoint2D p) ORTHANC_OVERRIDE;
     virtual void Highlight(ScenePoint2D p) ORTHANC_OVERRIDE;
     virtual void ResetHighlightState() ORTHANC_OVERRIDE;
     virtual boost::shared_ptr<IFlexiblePointerTracker> CreateEditionTracker(const PointerEvent& e) ORTHANC_OVERRIDE;
@@ -64,7 +64,7 @@
     };
 
 
-    LineHighlightArea LineHitTest(ScenePoint2D p) const;
+    LineHighlightArea LineHitTest(ScenePoint2D p);
 
   private:
     virtual void        RefreshScene() ORTHANC_OVERRIDE;
--- a/Framework/Scene2DViewport/MeasureCommands.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/MeasureCommands.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -20,6 +20,8 @@
 
 #include "MeasureCommands.h"
 
+#include <memory>
+
 #include <boost/make_shared.hpp>
 #include <boost/ref.hpp>
 
@@ -27,19 +29,21 @@
 {
   void CreateMeasureCommand::Undo()
   {
+    std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_.Lock());
     // simply disable the measure tool upon undo
     GetMeasureTool()->Disable();
-    GetController()->RemoveMeasureTool(GetMeasureTool());
+    lock->GetController().RemoveMeasureTool(GetMeasureTool());
   }
 
   void CreateMeasureCommand::Redo()
   {
+    std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_.Lock());
     GetMeasureTool()->Enable();
-    GetController()->AddMeasureTool(GetMeasureTool());
+    lock->GetController().AddMeasureTool(GetMeasureTool());
   }
 
-  CreateMeasureCommand::CreateMeasureCommand(boost::weak_ptr<ViewportController> controllerW)
-    : MeasureCommand(controllerW)
+  CreateMeasureCommand::CreateMeasureCommand(IViewport& viewport)
+    : MeasureCommand(viewport)
   {
 
   }
@@ -52,15 +56,17 @@
 
   void DeleteMeasureCommand::Redo()
   {
+    std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_.Lock());
     // simply disable the measure tool upon undo
     GetMeasureTool()->Disable();
-    GetController()->RemoveMeasureTool(GetMeasureTool());
+    lock->GetController().RemoveMeasureTool(GetMeasureTool());
   }
 
   void DeleteMeasureCommand::Undo()
   {
+    std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_.Lock());
     GetMeasureTool()->Enable();
-    GetController()->AddMeasureTool(GetMeasureTool());
+    lock->GetController().AddMeasureTool(GetMeasureTool());
   }
 
   DeleteMeasureCommand::~DeleteMeasureCommand()
@@ -69,18 +75,19 @@
     // we thus leave it as is
   }
 
-  DeleteMeasureCommand::DeleteMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW)
-    : MeasureCommand(controllerW)
+  DeleteMeasureCommand::DeleteMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, IViewport& viewport)
+    : MeasureCommand(viewport)
     , mementoOriginal_(measureTool->GetMemento())
     , measureTool_(measureTool)
     , mementoModified_(measureTool->GetMemento())
   {
+    std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_.Lock());
     GetMeasureTool()->Disable();
-    GetController()->RemoveMeasureTool(GetMeasureTool());
+    lock->GetController().RemoveMeasureTool(GetMeasureTool());
   }
 
-  EditMeasureCommand::EditMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW)
-    : MeasureCommand(controllerW)
+  EditMeasureCommand::EditMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, IViewport& viewport)
+    : MeasureCommand(viewport)
     , mementoOriginal_(measureTool->GetMemento())
     , mementoModified_(measureTool->GetMemento())
   {
@@ -102,11 +109,4 @@
   {
     GetMeasureTool()->SetMemento(mementoModified_);
   }
-
-  boost::shared_ptr<ViewportController> MeasureCommand::GetController()
-  {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    assert(controller); // accessing dead object?
-    return controller;
-  }
 }
--- a/Framework/Scene2DViewport/MeasureCommands.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/MeasureCommands.h	Wed Mar 04 09:45:38 2020 +0100
@@ -19,7 +19,7 @@
  **/
 #pragma once
 
-#include "../Scene2D/Scene2D.h"
+#include "../Viewport/IViewport.h"
 
 // to be moved into Stone
 #include "PredeclaredTypes.h"
@@ -35,27 +35,21 @@
   class MeasureCommand : public boost::noncopyable
   {
   public:
-    MeasureCommand(boost::weak_ptr<ViewportController> controllerW) 
-      : controllerW_(controllerW)
-    {
-
-    }
+    MeasureCommand(IViewport& viewport) : viewport_(viewport)
+    {}
     virtual void Undo() = 0;
     virtual void Redo() = 0;
     
     virtual ~MeasureCommand() {};
 
   protected:
-    boost::shared_ptr<ViewportController>  GetController();
-
-  private:
-    boost::weak_ptr<ViewportController> controllerW_;
+    IViewport& viewport_;
   };
 
   class CreateMeasureCommand : public MeasureCommand
   {
   public:
-    CreateMeasureCommand(boost::weak_ptr<ViewportController> controllerW);
+    CreateMeasureCommand(IViewport& viewport);
     virtual ~CreateMeasureCommand();
     virtual void Undo() ORTHANC_OVERRIDE;
     virtual void Redo() ORTHANC_OVERRIDE;
@@ -67,7 +61,7 @@
   class EditMeasureCommand : public MeasureCommand
   {
   public:
-    EditMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW);
+    EditMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, IViewport& viewport);
     virtual ~EditMeasureCommand();
     virtual void Undo() ORTHANC_OVERRIDE;
     virtual void Redo() ORTHANC_OVERRIDE;
@@ -88,7 +82,7 @@
   class DeleteMeasureCommand : public MeasureCommand
   {
   public:
-    DeleteMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, boost::weak_ptr<ViewportController> controllerW);
+    DeleteMeasureCommand(boost::shared_ptr<MeasureTool> measureTool, IViewport& viewport);
     virtual ~DeleteMeasureCommand();
     virtual void Undo() ORTHANC_OVERRIDE;
     virtual void Redo() ORTHANC_OVERRIDE;
--- a/Framework/Scene2DViewport/MeasureTool.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/MeasureTool.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -26,6 +26,8 @@
 
 #include <boost/math/constants/constants.hpp>
 
+#include "../Viewport/IViewport.h"
+
 namespace OrthancStone
 {
   void MeasureTool::Enable()
@@ -45,46 +47,26 @@
     return enabled_;
   }
 
-
-  boost::shared_ptr<const ViewportController> MeasureTool::GetController() const
-  {
-    boost::shared_ptr<const ViewportController> controller = controllerW_.lock();
-    if (!controller)
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
-        "Using dead ViewportController object!");
-    return controller;
-  }
-
-  boost::shared_ptr<ViewportController> MeasureTool::GetController()
-  {
-#if 1
-    return boost::const_pointer_cast<ViewportController>
-      (const_cast<const MeasureTool*>(this)->GetController());
-    //return boost::const_<boost::shared_ptr<ViewportController>>
-    //  (const_cast<const MeasureTool*>(this)->GetController());
-#else
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (!controller)
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, 
-        "Using dead ViewportController object!");
-    return controller;
-#endif
-  }
-
   MeasureTool::MeasureTool(
-    boost::weak_ptr<ViewportController> controllerW)
-    : controllerW_(controllerW)
+    IViewport& viewport)
+    : viewport_(viewport)
     , enabled_(true)
   {
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+
     // TODO => Move this out of constructor
-    Register<ViewportController::SceneTransformChanged>(*GetController(), &MeasureTool::OnSceneTransformChanged);
+    Register<ViewportController::SceneTransformChanged>(
+      controller, 
+      &MeasureTool::OnSceneTransformChanged);
   }
 
-
   bool MeasureTool::IsSceneAlive() const
   {
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    return (controller.get() != NULL);
+    // since the lifetimes of the viewport, viewportcontroller (and the
+    // measuring tools inside it) are linked, the scene is always alive as 
+    // long as "this" is alive
+    return true;
   }
 
   void MeasureTool::OnSceneTransformChanged(
--- a/Framework/Scene2DViewport/MeasureTool.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/MeasureTool.h	Wed Mar 04 09:45:38 2020 +0100
@@ -75,7 +75,7 @@
     true, then a click at that position will return a tracker to edit the 
     measuring tool
     */
-    virtual bool HitTest(ScenePoint2D p) const = 0;
+    virtual bool HitTest(ScenePoint2D p) = 0;
 
     /**
     This method must return a memento the captures the tool state (not including
@@ -113,7 +113,7 @@
     virtual std::string GetDescription() = 0;
 
   protected:
-    MeasureTool(boost::weak_ptr<ViewportController> controllerW);
+    MeasureTool(IViewport& viewport);
 
     /**
     The measuring tool may exist in a standalone fashion, without any available
@@ -129,17 +129,20 @@
     */
     virtual void RefreshScene() = 0;
 
-    boost::shared_ptr<const ViewportController> GetController() const;
-    boost::shared_ptr<ViewportController>      GetController();
-
     /**
     enabled_ is not accessible by subclasses because there is a state machine
     that we do not wanna mess with
     */
     bool IsEnabled() const;
 
+    /**
+    Protected to allow sub-classes to use this weak pointer in factory methods
+    (pass them to created objects)
+    */
+    IViewport& viewport_;
+
+
   private:
-    boost::weak_ptr<ViewportController> controllerW_;
     bool     enabled_;
   };
 
--- a/Framework/Scene2DViewport/MeasureTrackers.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/MeasureTrackers.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -24,8 +24,8 @@
 namespace OrthancStone
 {
 
-  CreateMeasureTracker::CreateMeasureTracker(boost::weak_ptr<ViewportController> controllerW)
-    : controllerW_(controllerW)
+  CreateMeasureTracker::CreateMeasureTracker(IViewport& viewport)
+    : viewport_(viewport)
     , alive_(true)
     , commitResult_(true)
   {
@@ -47,23 +47,28 @@
     // if the tracker completes successfully, we add the command
     // to the undo stack
     // otherwise, we simply undo it
+
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+
     if (commitResult_)
-      controllerW_.lock()->PushCommand(command_);
+      lock->GetController().PushCommand(command_);
     else
       command_->Undo();
+
+    lock->Invalidate();
   }
 
-  EditMeasureTracker::EditMeasureTracker(boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e)
-    : controllerW_(controllerW)
+  EditMeasureTracker::EditMeasureTracker(IViewport& viewport, const PointerEvent& e)
+    : viewport_(viewport)
     , alive_(true)
     , commitResult_(true)
   {
-    boost::shared_ptr<ViewportController> controller = controllerW.lock();
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
 
-    if (controller)
-    {
-      originalClickPosition_ = e.GetMainPosition().Apply(controller->GetScene().GetCanvasToSceneTransform());
-    }
+    originalClickPosition_ = e.GetMainPosition().Apply(
+      controller.GetScene().GetCanvasToSceneTransform());
   }
 
   void EditMeasureTracker::Cancel()
@@ -82,10 +87,16 @@
     // if the tracker completes successfully, we add the command
     // to the undo stack
     // otherwise, we simply undo it
+
+    std::unique_ptr<IViewport::ILock> lock(viewport_.Lock());
+    ViewportController& controller = lock->GetController();
+
     if (commitResult_)
-      controllerW_.lock()->PushCommand(command_);
+      lock->GetController().PushCommand(command_);
     else
       command_->Undo();
+
+    lock->Invalidate();
   }
 }
 
--- a/Framework/Scene2DViewport/MeasureTrackers.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/MeasureTrackers.h	Wed Mar 04 09:45:38 2020 +0100
@@ -40,13 +40,13 @@
     virtual void Cancel() ORTHANC_OVERRIDE;
     virtual bool IsAlive() const ORTHANC_OVERRIDE;
   protected:
-    CreateMeasureTracker(boost::weak_ptr<ViewportController> controllerW);
+    CreateMeasureTracker(IViewport& viewport);
 
     ~CreateMeasureTracker();
   
   protected:
     boost::shared_ptr<CreateMeasureCommand>         command_;
-    boost::weak_ptr<ViewportController>          controllerW_;
+    IViewport&          viewport_;
     bool                            alive_;
 
   private:
@@ -59,13 +59,13 @@
     virtual void Cancel() ORTHANC_OVERRIDE;
     virtual bool IsAlive() const ORTHANC_OVERRIDE;
   protected:
-    EditMeasureTracker(boost::weak_ptr<ViewportController> controllerW, const PointerEvent& e);
+    EditMeasureTracker(IViewport& viewport, const PointerEvent& e);
 
     ~EditMeasureTracker();
 
   protected:
     boost::shared_ptr<EditMeasureCommand> command_;
-    boost::weak_ptr<ViewportController>   controllerW_;
+    IViewport&   viewport_;
     bool                                  alive_;
     
     ScenePoint2D                          GetOriginalClickPosition() const
--- a/Framework/Scene2DViewport/OneGesturePointerTracker.cpp	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/OneGesturePointerTracker.cpp	Wed Mar 04 09:45:38 2020 +0100
@@ -28,8 +28,8 @@
 namespace OrthancStone
 {
   OneGesturePointerTracker::OneGesturePointerTracker(
-    boost::weak_ptr<ViewportController> controllerW)
-    : controllerW_(controllerW)
+    IViewport& viewport)
+    : viewport_(viewport)
     , alive_(true)
     , currentTouchCount_(1)
   {
@@ -60,7 +60,7 @@
      * 2019-12-06 (SJO): Patch to have consistent behavior when mouse
      * leaves the canvas while the tracker is still active, then
      * button is released while out-of-canvas. Such an event is not
-     * catched (at least in WebAssembly), so we delete the tracker on
+     * caught (at least in WebAssembly), so we delete the tracker on
      * the next click inside the canvas.
      **/
     alive_ = false;
@@ -70,9 +70,4 @@
   {
     return alive_;
   }
-
-  boost::shared_ptr<ViewportController> OneGesturePointerTracker::GetController()
-  {
-    return controllerW_.lock();
-  }
 }
--- a/Framework/Scene2DViewport/OneGesturePointerTracker.h	Wed Mar 04 09:44:34 2020 +0100
+++ b/Framework/Scene2DViewport/OneGesturePointerTracker.h	Wed Mar 04 09:45:38 2020 +0100
@@ -22,6 +22,11 @@
 
 #include "IFlexiblePointerTracker.h"
 
+#include "../Viewport/IViewport.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
 namespace OrthancStone
 {
   /**
@@ -39,16 +44,15 @@
   class OneGesturePointerTracker : public IFlexiblePointerTracker
   {
   public:
-    OneGesturePointerTracker(boost::weak_ptr<ViewportController> controllerW);
+    OneGesturePointerTracker(IViewport& viewport);
     virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE;
     virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE;
     virtual bool IsAlive() const ORTHANC_OVERRIDE;
   
   protected:
-    boost::shared_ptr<ViewportController>  GetController();
+    IViewport& viewport_;
 
   private:
-    boost::weak_ptr<ViewportController> controllerW_;
     bool                   alive_;
     int                    currentTouchCount_;
   };