changeset 1972:9c0adcc8feec

refactoring to simplify OneGesturePointerTracker
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 28 Oct 2022 16:21:28 +0200
parents e5b31d55206d
children 596f4752fa42
files OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.cpp OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.h OrthancStone/Sources/Scene2D/Internals/FixedPointAligner.cpp OrthancStone/Sources/Scene2D/Internals/FixedPointAligner.h OrthancStone/Sources/Scene2D/PanSceneTracker.cpp OrthancStone/Sources/Scene2D/PanSceneTracker.h OrthancStone/Sources/Scene2D/RotateSceneTracker.cpp OrthancStone/Sources/Scene2D/RotateSceneTracker.h OrthancStone/Sources/Scene2D/ZoomSceneTracker.cpp OrthancStone/Sources/Scene2D/ZoomSceneTracker.h OrthancStone/Sources/Scene2DViewport/CreateAngleMeasureTracker.cpp OrthancStone/Sources/Scene2DViewport/CreateAngleMeasureTracker.h OrthancStone/Sources/Scene2DViewport/CreateLineMeasureTracker.cpp OrthancStone/Sources/Scene2DViewport/CreateLineMeasureTracker.h OrthancStone/Sources/Scene2DViewport/EditAngleMeasureTracker.cpp OrthancStone/Sources/Scene2DViewport/EditAngleMeasureTracker.h OrthancStone/Sources/Scene2DViewport/EditLineMeasureTracker.cpp OrthancStone/Sources/Scene2DViewport/EditLineMeasureTracker.h OrthancStone/Sources/Scene2DViewport/IFlexiblePointerTracker.h OrthancStone/Sources/Scene2DViewport/OneGesturePointerTracker.cpp OrthancStone/Sources/Scene2DViewport/OneGesturePointerTracker.h OrthancStone/Sources/Scene2DViewport/ViewportController.cpp
diffstat 24 files changed, 263 insertions(+), 213 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake	Fri Oct 28 16:21:28 2022 +0200
@@ -445,8 +445,9 @@
   ${ORTHANC_STONE_ROOT}/Toolbox/UnionOfRectangles.cpp
   ${ORTHANC_STONE_ROOT}/Toolbox/UnionOfRectangles.h
   
+  ${ORTHANC_STONE_ROOT}/Viewport/DefaultViewportInteractor.cpp
   ${ORTHANC_STONE_ROOT}/Viewport/IViewport.h
-  ${ORTHANC_STONE_ROOT}/Viewport/DefaultViewportInteractor.cpp
+  ${ORTHANC_STONE_ROOT}/Viewport/ViewportLocker.cpp
   
   ${ORTHANC_STONE_ROOT}/Volumes/IGeometryProvider.h
   ${ORTHANC_STONE_ROOT}/Volumes/IVolumeSlicer.cpp
--- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -736,20 +736,23 @@
     {
     }
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
       primitive_.MovePreview(event.GetMainPosition().Apply(canvasToScene_) - sceneClick_);
       that_.BroadcastMessage(AnnotationChangedMessage(that_));
     }
       
-    virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerUp(const PointerEvent& event,
+                           const Scene2D& scene) ORTHANC_OVERRIDE
     {
       primitive_.MoveDone(event.GetMainPosition().Apply(canvasToScene_) - sceneClick_);
       alive_ = false;
       that_.BroadcastMessage(AnnotationChangedMessage(that_));
     }
 
-    virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerDown(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
     }
 
@@ -1221,7 +1224,8 @@
              handle2_ != NULL);
     }
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
       if (annotation_ != NULL)
       {
@@ -1233,14 +1237,16 @@
       }
     }
       
-    virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerUp(const PointerEvent& event,
+                           const Scene2D& scene) ORTHANC_OVERRIDE
     {
       annotation_ = NULL;  // IsAlive() becomes false
 
       that_.BroadcastMessage(AnnotationAddedMessage(that_));
     }
 
-    virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerDown(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
     }
 
@@ -1281,7 +1287,8 @@
       segment_ = new SegmentAnnotation(that, units, false /* no length label */, sceneClick, sceneClick);
     }
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
       if (segment_ != NULL)
       {
@@ -1298,7 +1305,8 @@
       }
     }
       
-    virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerUp(const PointerEvent& event,
+                           const Scene2D& scene) ORTHANC_OVERRIDE
     {
       if (segment_ != NULL)
       {
@@ -1321,7 +1329,8 @@
       }
     }
 
-    virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerDown(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
     }
 
@@ -1357,15 +1366,18 @@
     {
     }
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
     }
       
-    virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerUp(const PointerEvent& event,
+                           const Scene2D& scene) ORTHANC_OVERRIDE
     {
     }
 
-    virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE
+    virtual void PointerDown(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE
     {
     }
 
@@ -1566,6 +1578,10 @@
   IFlexiblePointerTracker* AnnotationsSceneLayer::CreateTracker(const ScenePoint2D& p,
                                                                 const Scene2D& scene)
   {
+    /**
+     * WARNING: The created trackers must NOT keep a reference to "scene"!
+     **/
+
     if (activeTool_ == Tool_None)
     {
       return NULL;
--- a/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -118,7 +118,7 @@
                                                                  const PointerEvent& event,
                                                                  unsigned int canvasWidth,
                                                                  unsigned int canvasHeight) :
-    OneGesturePointerTracker(viewport),
+    viewport_(viewport),
     layerIndex_(layerIndex),
     clickX_(event.GetMainPosition().GetX()),
     clickY_(event.GetMainPosition().GetY())
@@ -154,7 +154,8 @@
     }
   }
   
-  void GrayscaleWindowingSceneTracker::PointerMove(const PointerEvent& event)
+  void GrayscaleWindowingSceneTracker::PointerMove(const PointerEvent& event,
+                                                   const Scene2D& scene)
   {
     if (active_)
     {
--- a/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -23,10 +23,8 @@
 
 #pragma once
 
-
 #include "../Scene2DViewport/OneGesturePointerTracker.h"
 #include "../Viewport/IViewport.h"
-#include "Internals/FixedPointAligner.h"
 
 #include <boost/weak_ptr.hpp>
 
@@ -35,6 +33,8 @@
   class GrayscaleWindowingSceneTracker : public OneGesturePointerTracker
   {
   private:
+    boost::weak_ptr<IViewport> viewport_;
+    
     bool    active_;
     int     layerIndex_;
     double  normalization_;
@@ -53,7 +53,8 @@
                                    unsigned int canvasWidth,
                                    unsigned int canvasHeight);
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
     
     virtual void Cancel() ORTHANC_OVERRIDE;
   };
--- a/OrthancStone/Sources/Scene2D/Internals/FixedPointAligner.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/Internals/FixedPointAligner.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -20,43 +20,31 @@
  * <http://www.gnu.org/licenses/>.
  **/
 
-#include "../../Scene2DViewport/ViewportController.h"
+
 #include "FixedPointAligner.h"
 
+#include <OrthancException.h>
+
 namespace OrthancStone
 {
   namespace Internals
   {
-    FixedPointAligner::FixedPointAligner(boost::weak_ptr<IViewport> viewport,
-                                         const ScenePoint2D& p) 
-      : viewport_(viewport)
-      , canvas_(p)
+    FixedPointAligner::FixedPointAligner(ViewportController& controller,
+                                         const ScenePoint2D& p) :
+      canvas_(p)
     {
-      std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-      pivot_ = canvas_.Apply(lock->GetController().GetCanvasToSceneTransform());
+      pivot_ = canvas_.Apply(controller.GetCanvasToSceneTransform());
     }
 
-    IViewport::ILock* FixedPointAligner::GetViewportLock()
+    void FixedPointAligner::Apply(ViewportController& controller)
     {
-      boost::shared_ptr<IViewport> viewport = viewport_.lock();
-      if (viewport)
-        return viewport->Lock();
-      else
-        return NULL;
-    }
-    
-    void FixedPointAligner::Apply()
-    {
-      std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-      ScenePoint2D p = canvas_.Apply(
-        lock->GetController().GetCanvasToSceneTransform());
+      ScenePoint2D p = canvas_.Apply(controller.GetCanvasToSceneTransform());
 
-      lock->GetController().SetSceneToCanvasTransform(
+      controller.SetSceneToCanvasTransform(
         AffineTransform2D::Combine(
-          lock->GetController().GetSceneToCanvasTransform(),
+          controller.GetSceneToCanvasTransform(),
           AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
                                           p.GetY() - pivot_.GetY())));
-      lock->Invalidate();
     }
   }
 }
--- a/OrthancStone/Sources/Scene2D/Internals/FixedPointAligner.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/Internals/FixedPointAligner.h	Fri Oct 28 16:21:28 2022 +0200
@@ -22,11 +22,7 @@
 
 #pragma once
 
-#include "../../Scene2DViewport/PredeclaredTypes.h"
-#include "../../Scene2D/ScenePoint2D.h"
-#include "../../Viewport/IViewport.h"
-
-#include <boost/weak_ptr.hpp>
+#include "../../Scene2DViewport/ViewportController.h"
 
 namespace OrthancStone
 {
@@ -37,21 +33,14 @@
     class FixedPointAligner : public boost::noncopyable
     {
     private:
-      boost::weak_ptr<IViewport> viewport_;
-      ScenePoint2D               pivot_;
-      ScenePoint2D               canvas_;
-
-      /**
-      This will return a scoped lock to the viewport.
-      If the viewport does not exist anymore, then nullptr is returned.
-      */
-      IViewport::ILock* GetViewportLock();
+      ScenePoint2D  pivot_;
+      ScenePoint2D  canvas_;
 
     public:
-      FixedPointAligner(boost::weak_ptr<IViewport> viewport,
+      FixedPointAligner(ViewportController& controller,
                         const ScenePoint2D& p);
 
-      void Apply();
+      void Apply(ViewportController& controller);
     };
   }
 }
--- a/OrthancStone/Sources/Scene2D/PanSceneTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/PanSceneTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -22,44 +22,52 @@
 
 
 #include "PanSceneTracker.h"
-#include "../Viewport/IViewport.h"
+
 #include "../Scene2DViewport/ViewportController.h"
-
-#include <memory>
+#include "../Viewport/ViewportLocker.h"
 
 namespace OrthancStone
 {
   PanSceneTracker::PanSceneTracker(boost::weak_ptr<IViewport> viewport,
-                                   const PointerEvent& event)
-    : OneGesturePointerTracker(viewport)
+                                   const PointerEvent& event) :
+    viewport_(viewport)
   {
+    ViewportLocker locker(viewport_);
     
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-
-    originalSceneToCanvas_ = lock->GetController().GetSceneToCanvasTransform();
-    originalCanvasToScene_ = lock->GetController().GetCanvasToSceneTransform();
-
-    pivot_ = event.GetMainPosition().Apply(originalCanvasToScene_);
+    if (locker.IsValid())
+    {
+      originalSceneToCanvas_ = locker.GetController().GetSceneToCanvasTransform();
+      originalCanvasToScene_ = locker.GetController().GetCanvasToSceneTransform();
+      pivot_ = event.GetMainPosition().Apply(originalCanvasToScene_);
+    }
   }
 
 
-  void PanSceneTracker::PointerMove(const PointerEvent& event)
+  void PanSceneTracker::PointerMove(const PointerEvent& event,
+                                    const Scene2D& scene)
   {
     ScenePoint2D p = event.GetMainPosition().Apply(originalCanvasToScene_);
 
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-
-    lock->GetController().SetSceneToCanvasTransform(
-      AffineTransform2D::Combine(
-        originalSceneToCanvas_,
-        AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
-                                        p.GetY() - pivot_.GetY())));
-    lock->Invalidate();
+    ViewportLocker locker(viewport_);
+    
+    if (locker.IsValid())
+    {
+      locker.GetController().SetSceneToCanvasTransform(
+        AffineTransform2D::Combine(
+          originalSceneToCanvas_,
+          AffineTransform2D::CreateOffset(p.GetX() - pivot_.GetX(),
+                                          p.GetY() - pivot_.GetY())));
+      locker.Invalidate();
+    }
   }
 
   void PanSceneTracker::Cancel()
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-    lock->GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
+    ViewportLocker locker(viewport_);
+    
+    if (locker.IsValid())
+    {
+      locker.GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
+    }
   }
 }
--- a/OrthancStone/Sources/Scene2D/PanSceneTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/PanSceneTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -29,17 +29,19 @@
 {
   class PanSceneTracker : public OneGesturePointerTracker
   {
+  private:
+    boost::weak_ptr<IViewport> viewport_;
+    ScenePoint2D               pivot_;
+    AffineTransform2D          originalSceneToCanvas_;
+    AffineTransform2D          originalCanvasToScene_;
+
   public:
     PanSceneTracker(boost::weak_ptr<IViewport> viewport,
                     const PointerEvent& event);
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
     
     virtual void Cancel() ORTHANC_OVERRIDE;
-
-  private:
-    ScenePoint2D           pivot_;
-    AffineTransform2D      originalSceneToCanvas_;
-    AffineTransform2D      originalCanvasToScene_;
   };
 }
--- a/OrthancStone/Sources/Scene2D/RotateSceneTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/RotateSceneTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -21,57 +21,73 @@
  **/
 
 #include "RotateSceneTracker.h"
+
 #include "../Scene2DViewport/ViewportController.h"
+#include "../Viewport/ViewportLocker.h"
 
 namespace OrthancStone
 {
   RotateSceneTracker::RotateSceneTracker(boost::weak_ptr<IViewport> viewport,
                                          const PointerEvent& event) :
-    OneGesturePointerTracker(viewport),
+    viewport_(viewport),
     click_(event.GetMainPosition()),
-    aligner_(viewport, click_),
     referenceAngle_(0),
     isFirst_(true)
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-    originalSceneToCanvas_ = lock->GetController().GetSceneToCanvasTransform();
+    ViewportLocker locker(viewport_);
+    
+    if (locker.IsValid())
+    {
+      aligner_.reset(new Internals::FixedPointAligner(locker.GetController(), click_));
+      originalSceneToCanvas_ = locker.GetController().GetSceneToCanvasTransform();
+    }
   }
 
   
-  void RotateSceneTracker::PointerMove(const PointerEvent& event)
+  void RotateSceneTracker::PointerMove(const PointerEvent& event,
+                                       const Scene2D& scene)
   {
-    ScenePoint2D p = event.GetMainPosition();
-    double dx = p.GetX() - click_.GetX();
-    double dy = p.GetY() - click_.GetY();
+    if (aligner_.get() != NULL)
+    {
+      ScenePoint2D p = event.GetMainPosition();
+      double dx = p.GetX() - click_.GetX();
+      double dy = p.GetY() - click_.GetY();
 
-    if (std::abs(dx) > 5.0 ||
-        std::abs(dy) > 5.0)
-    {
-      double a = atan2(dy, dx);
-
-      if (isFirst_)
+      if (std::abs(dx) > 5.0 ||
+          std::abs(dy) > 5.0)
       {
-        referenceAngle_ = a;
-        isFirst_ = false;
-      }
+        double a = atan2(dy, dx);
 
-      std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
+        if (isFirst_)
+        {
+          referenceAngle_ = a;
+          isFirst_ = false;
+        }
 
-      lock->GetController().SetSceneToCanvasTransform(
-        AffineTransform2D::Combine(
-          AffineTransform2D::CreateRotation(a - referenceAngle_),
-          originalSceneToCanvas_));
-      aligner_.Apply();
-      lock->Invalidate();
+        ViewportLocker locker(viewport_);
+    
+        if (locker.IsValid())
+        {
+          locker.GetController().SetSceneToCanvasTransform(
+            AffineTransform2D::Combine(
+              AffineTransform2D::CreateRotation(a - referenceAngle_),
+              originalSceneToCanvas_));
+          aligner_->Apply(locker.GetController());
+          locker.Invalidate();
+        }
+      }
     }
   }
 
   
   void RotateSceneTracker::Cancel()
   {
-    // See remark above
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-    lock->GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
-    lock->Invalidate();
+    ViewportLocker locker(viewport_);
+    
+    if (locker.IsValid())
+    {
+      locker.GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
+      locker.Invalidate();
+    }
   }
 }
--- a/OrthancStone/Sources/Scene2D/RotateSceneTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/RotateSceneTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -32,17 +32,20 @@
   class RotateSceneTracker : public OneGesturePointerTracker
   {
   private:
+    boost::weak_ptr<IViewport>   viewport_;
     ScenePoint2D                 click_;
-    Internals::FixedPointAligner aligner_;
     double                       referenceAngle_;
     bool                         isFirst_;
     AffineTransform2D            originalSceneToCanvas_;
 
+    std::unique_ptr<Internals::FixedPointAligner>  aligner_;
+    
   public:
     RotateSceneTracker(boost::weak_ptr<IViewport> viewport,
                        const PointerEvent& event);
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
     
     virtual void Cancel() ORTHANC_OVERRIDE;
   };
--- a/OrthancStone/Sources/Scene2D/ZoomSceneTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/ZoomSceneTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -22,38 +22,39 @@
 
 
 #include "ZoomSceneTracker.h"
+
 #include "../Scene2DViewport/ViewportController.h"
+#include "../Viewport/ViewportLocker.h"
 
 namespace OrthancStone
 {
   ZoomSceneTracker::ZoomSceneTracker(boost::weak_ptr<IViewport> viewport,
                                      const PointerEvent& event,
-                                     unsigned int canvasHeight)
-    : OneGesturePointerTracker(viewport)
-    , clickY_(event.GetMainPosition().GetY())
-    , aligner_(viewport, event.GetMainPosition())
-  {
+                                     unsigned int canvasHeight) :
+    viewport_(viewport),
+    clickY_(event.GetMainPosition().GetY())
+  {    
+    ViewportLocker locker(viewport_);
     
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-    originalSceneToCanvas_ = lock->GetController().GetSceneToCanvasTransform();
+    if (locker.IsValid())
+    {
+      originalSceneToCanvas_ = locker.GetController().GetSceneToCanvasTransform();
 
-    if (canvasHeight <= 3)
-    {
-      active_ = false;
-    }
-    else
-    {
-      normalization_ = 1.0 / static_cast<double>(canvasHeight - 1);
-      active_ = true;
+      if (canvasHeight > 3)
+      {
+        normalization_ = 1.0 / static_cast<double>(canvasHeight - 1);
+        aligner_.reset(new Internals::FixedPointAligner(locker.GetController(), event.GetMainPosition()));
+      }
     }
   }
   
-  void ZoomSceneTracker::PointerMove(const PointerEvent& event)
+  void ZoomSceneTracker::PointerMove(const PointerEvent& event,
+                                     const Scene2D& scene)
   {
     static const double MIN_ZOOM = -4;
     static const double MAX_ZOOM = 4;
       
-    if (active_)
+    if (aligner_.get() != NULL)
     {
       double y = event.GetMainPosition().GetY();
       
@@ -78,20 +79,28 @@
 
       double zoom = pow(2.0, z);
 
-      std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-      lock->GetController().SetSceneToCanvasTransform(
-        AffineTransform2D::Combine(
-          AffineTransform2D::CreateScaling(zoom, zoom),
-          originalSceneToCanvas_));
-      aligner_.Apply();
-      lock->Invalidate();
+      ViewportLocker locker(viewport_);
+    
+      if (locker.IsValid())
+      {
+        locker.GetController().SetSceneToCanvasTransform(
+          AffineTransform2D::Combine(
+            AffineTransform2D::CreateScaling(zoom, zoom),
+            originalSceneToCanvas_));
+        aligner_->Apply(locker.GetController());
+        locker.Invalidate();
+      }
     }
   }
 
   void ZoomSceneTracker::Cancel()
   {
-    std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
-    lock->GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
-    lock->Invalidate();
+    ViewportLocker locker(viewport_);
+    
+    if (locker.IsValid())
+    {
+      locker.GetController().SetSceneToCanvasTransform(originalSceneToCanvas_);
+      locker.Invalidate();
+    }
   }
 }
--- a/OrthancStone/Sources/Scene2D/ZoomSceneTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2D/ZoomSceneTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -34,20 +34,22 @@
 {
   class ZoomSceneTracker : public OneGesturePointerTracker
   {
+  private:
+    boost::weak_ptr<IViewport>    viewport_;
+    double                        clickY_;
+    double                        normalization_;
+    AffineTransform2D             originalSceneToCanvas_;
+
+    std::unique_ptr<Internals::FixedPointAligner>  aligner_;
+    
   public:
     ZoomSceneTracker(boost::weak_ptr<IViewport> viewport,
                      const PointerEvent& event,
                      unsigned int canvasHeight);
 
-    virtual void PointerMove(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
+    
     virtual void Cancel() ORTHANC_OVERRIDE;
-  
-  private:
-    double                        clickY_;
-    bool                          active_;
-    double                        normalization_;
-    Internals::FixedPointAligner  aligner_;
-    AffineTransform2D             originalSceneToCanvas_;
-
   };
 }
--- a/OrthancStone/Sources/Scene2DViewport/CreateAngleMeasureTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/CreateAngleMeasureTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -47,7 +47,8 @@
   {
   }
 
-  void CreateAngleMeasureTracker::PointerMove(const PointerEvent& event)
+  void CreateAngleMeasureTracker::PointerMove(const PointerEvent& event,
+                                              const Scene2D& scene)
   {
     if (!alive_)
     {
@@ -83,7 +84,8 @@
     }
   }
 
-  void CreateAngleMeasureTracker::PointerUp(const PointerEvent& e)
+  void CreateAngleMeasureTracker::PointerUp(const PointerEvent& e,
+                                            const Scene2D& scene)
   {
     // TODO: the current app does not prevent multiple PointerDown AND
     // PointerUp to be sent to the tracker.
@@ -108,7 +110,8 @@
     }
   }
 
-  void CreateAngleMeasureTracker::PointerDown(const PointerEvent& e)
+  void CreateAngleMeasureTracker::PointerDown(const PointerEvent& e,
+                                              const Scene2D& scene)
   {
     switch (state_)
     {
--- a/OrthancStone/Sources/Scene2DViewport/CreateAngleMeasureTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/CreateAngleMeasureTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -45,9 +45,14 @@
 
     ~CreateAngleMeasureTracker();
 
-    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
+    
+    virtual void PointerUp(const PointerEvent& e,
+                           const Scene2D& scene) ORTHANC_OVERRIDE;
+    
+    virtual void PointerDown(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
 
   private:
     boost::shared_ptr<CreateAngleMeasureCommand> GetCommand();
--- a/OrthancStone/Sources/Scene2DViewport/CreateLineMeasureTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/CreateLineMeasureTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -48,7 +48,8 @@
 
   }
 
-  void CreateLineMeasureTracker::PointerMove(const PointerEvent& event)
+  void CreateLineMeasureTracker::PointerMove(const PointerEvent& event,
+                                             const Scene2D& scene)
   {
     if (!alive_)
     {
@@ -73,7 +74,8 @@
     GetCommand()->SetEnd(scenePos);
   }
 
-  void CreateLineMeasureTracker::PointerUp(const PointerEvent& e)
+  void CreateLineMeasureTracker::PointerUp(const PointerEvent& e,
+                                           const Scene2D& scene)
   {
     // TODO: the current app does not prevent multiple PointerDown AND
     // PointerUp to be sent to the tracker.
@@ -83,7 +85,8 @@
     alive_ = false;
   }
 
-  void CreateLineMeasureTracker::PointerDown(const PointerEvent& e)
+  void CreateLineMeasureTracker::PointerDown(const PointerEvent& e,
+                                             const Scene2D& scene)
   {
     LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) "
       "are ignored when the line measure creation tracker is active";
--- a/OrthancStone/Sources/Scene2DViewport/CreateLineMeasureTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/CreateLineMeasureTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -45,9 +45,12 @@
 
     ~CreateLineMeasureTracker();
 
-    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
+    virtual void PointerUp(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
+    virtual void PointerDown(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
 
   private:
     boost::shared_ptr<CreateLineMeasureCommand> GetCommand();
--- a/OrthancStone/Sources/Scene2DViewport/EditAngleMeasureTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/EditAngleMeasureTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -50,15 +50,16 @@
 
   }
 
-  void EditAngleMeasureTracker::PointerMove(const PointerEvent& e)
+  void EditAngleMeasureTracker::PointerMove(const PointerEvent& e,
+                                            const Scene2D& scene)
   {
     std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
     
     ViewportController& controller = lock->GetController();
-    const Scene2D& scene = controller.GetScene();
+    const Scene2D& scene2 = controller.GetScene();
 
     ScenePoint2D scenePos = e.GetMainPosition().Apply(
-      scene.GetCanvasToSceneTransform());
+      scene2.GetCanvasToSceneTransform());
 
     ScenePoint2D delta = scenePos - GetOriginalClickPosition();
 
@@ -106,12 +107,14 @@
     }
   }
 
-  void EditAngleMeasureTracker::PointerUp(const PointerEvent& e)
+  void EditAngleMeasureTracker::PointerUp(const PointerEvent& e,
+                                          const Scene2D& scene)
   {
     alive_ = false;
   }
 
-  void EditAngleMeasureTracker::PointerDown(const PointerEvent& e)
+  void EditAngleMeasureTracker::PointerDown(const PointerEvent& e,
+                                            const Scene2D& scene)
   {
     LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) "
       "are ignored when the edit angle tracker is active";
--- a/OrthancStone/Sources/Scene2DViewport/EditAngleMeasureTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/EditAngleMeasureTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -45,9 +45,14 @@
 
     ~EditAngleMeasureTracker();
 
-    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
-    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
+    
+    virtual void PointerUp(const PointerEvent& e,
+                           const Scene2D& scene) ORTHANC_OVERRIDE;
+    
+    virtual void PointerDown(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
 
   private:
     AngleMeasureTool::AngleHighlightArea modifiedZone_;
--- a/OrthancStone/Sources/Scene2DViewport/EditLineMeasureTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/EditLineMeasureTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -46,14 +46,15 @@
     command_.reset(new EditLineMeasureCommand(measureTool, viewport));
   }
 
-  void EditLineMeasureTracker::PointerMove(const PointerEvent& e)
+  void EditLineMeasureTracker::PointerMove(const PointerEvent& e,
+                                           const Scene2D& scene)
   {
     std::unique_ptr<IViewport::ILock> lock(GetViewportLock());
     ViewportController& controller = lock->GetController();
-    const Scene2D& scene = controller.GetScene();
+    const Scene2D& scene2 = controller.GetScene();
 
     ScenePoint2D scenePos = e.GetMainPosition().Apply(
-      scene.GetCanvasToSceneTransform());
+      scene2.GetCanvasToSceneTransform());
 
     ScenePoint2D delta = scenePos - GetOriginalClickPosition();
 
@@ -91,12 +92,14 @@
     }
   }
 
-  void EditLineMeasureTracker::PointerUp(const PointerEvent& e)
+  void EditLineMeasureTracker::PointerUp(const PointerEvent& e,
+                                         const Scene2D& scene)
   {
     alive_ = false;
   }
 
-  void EditLineMeasureTracker::PointerDown(const PointerEvent& e)
+  void EditLineMeasureTracker::PointerDown(const PointerEvent& e,
+                                           const Scene2D& scene)
   {
     LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) "
       "are ignored when the edit line tracker is active";
--- a/OrthancStone/Sources/Scene2DViewport/EditLineMeasureTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/EditLineMeasureTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -48,10 +48,13 @@
       boost::weak_ptr<IViewport>      viewport,
       const PointerEvent&             e);
 
-    virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerMove(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
     
-    virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerUp(const PointerEvent& e,
+                           const Scene2D& scene) ORTHANC_OVERRIDE;
     
-    virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE;
+    virtual void PointerDown(const PointerEvent& e,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
   };
 }
--- a/OrthancStone/Sources/Scene2DViewport/IFlexiblePointerTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/IFlexiblePointerTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -45,13 +45,15 @@
     /**
     This method will be repeatedly called during user interaction
     */
-    virtual void PointerMove(const PointerEvent& event) = 0;
+    virtual void PointerMove(const PointerEvent& event,
+                             const Scene2D& scene) = 0;
 
     /**
     This method will be called when a touch/pointer is removed (mouse up, 
     pen lift, finger removed...)
     */
-    virtual void PointerUp(const PointerEvent& event) = 0;
+    virtual void PointerUp(const PointerEvent& event,
+                           const Scene2D& scene) = 0;
 
     /**
     This method will be called when a touch/pointer is added (mouse down, 
@@ -63,7 +65,8 @@
     Thus, if you count the PointerDown vs PointerUp, there will be an extra
     PointerUp.
     */
-    virtual void PointerDown(const PointerEvent& event) = 0;
+    virtual void PointerDown(const PointerEvent& event,
+                             const Scene2D& scene) = 0;
 
     /**
     This method will be repeatedly called by the tracker owner (for instance,
--- a/OrthancStone/Sources/Scene2DViewport/OneGesturePointerTracker.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/OneGesturePointerTracker.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -29,23 +29,14 @@
 
 namespace OrthancStone
 {
-  OneGesturePointerTracker::OneGesturePointerTracker(boost::weak_ptr<IViewport> viewport) :
+  OneGesturePointerTracker::OneGesturePointerTracker() :
     alive_(true),
-    currentTouchCount_(1),
-    viewport_(viewport)
+    currentTouchCount_(1)
   {
   }
 
-  IViewport::ILock* OneGesturePointerTracker::GetViewportLock()
-  {
-    boost::shared_ptr<IViewport> viewport = viewport_.lock();
-    if (viewport)
-      return viewport->Lock();
-    else
-      return NULL;
-  }
-
-  void OneGesturePointerTracker::PointerUp(const PointerEvent& event)
+  void OneGesturePointerTracker::PointerUp(const PointerEvent& event,
+                                           const Scene2D& scene)
   {
     // pointer up is only called for the LAST up event in case of a multi-touch
     // gesture
@@ -59,7 +50,8 @@
     }
   }
 
-  void OneGesturePointerTracker::PointerDown(const PointerEvent& event)
+  void OneGesturePointerTracker::PointerDown(const PointerEvent& event,
+                                             const Scene2D& scene)
   {
     // additional touches are not taken into account but we need to count 
     // the number of active touches
--- a/OrthancStone/Sources/Scene2DViewport/OneGesturePointerTracker.h	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/OneGesturePointerTracker.h	Fri Oct 28 16:21:28 2022 +0200
@@ -24,8 +24,6 @@
 
 #include "IFlexiblePointerTracker.h"
 
-#include "../Viewport/IViewport.h"
-
 #include <Compatibility.h>  // For ORTHANC_OVERRIDE
 
 #include <boost/shared_ptr.hpp>
@@ -51,21 +49,14 @@
     bool  alive_;
     int   currentTouchCount_;
 
-  protected:
-    boost::weak_ptr<IViewport> viewport_;
-
-    /**
-    This will return a scoped lock to the viewport.
-    If the viewport does not exist anymore, then nullptr is returned.
-    */
-    IViewport::ILock* GetViewportLock();
-
   public:
-    explicit OneGesturePointerTracker(boost::weak_ptr<IViewport> viewport);
+    explicit OneGesturePointerTracker();
     
-    virtual void PointerUp(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerUp(const PointerEvent& event,
+                           const Scene2D& scene) ORTHANC_OVERRIDE;
     
-    virtual void PointerDown(const PointerEvent& event) ORTHANC_OVERRIDE;
+    virtual void PointerDown(const PointerEvent& event,
+                             const Scene2D& scene) ORTHANC_OVERRIDE;
     
     virtual bool IsAlive() const ORTHANC_OVERRIDE;
   };
--- a/OrthancStone/Sources/Scene2DViewport/ViewportController.cpp	Fri Oct 28 13:38:19 2022 +0200
+++ b/OrthancStone/Sources/Scene2DViewport/ViewportController.cpp	Fri Oct 28 16:21:28 2022 +0200
@@ -222,7 +222,7 @@
     {
       // We are dealing with a multi-stage tracker (that is made of several 
       // interactions)
-      activeTracker_->PointerDown(event);
+      activeTracker_->PointerDown(event, GetScene());
 
       if (!activeTracker_->IsAlive())
       {
@@ -253,7 +253,7 @@
   {
     if (activeTracker_)
     {
-      activeTracker_->PointerMove(event);
+      activeTracker_->PointerMove(event, GetScene());
       return true;
     }
     else
@@ -266,7 +266,7 @@
   {
     if (activeTracker_)
     {
-      activeTracker_->PointerUp(event);
+      activeTracker_->PointerUp(event, GetScene());
 
       if (!activeTracker_->IsAlive())
       {