changeset 2347:b867b9180ac5 refactoring

simplified GrayscaleWindowingSceneTracker
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 06 Oct 2026 18:13:47 +0200
parents aa15732517f6
children 36b4b8f2cf32
files Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.cpp OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.h OrthancStone/Sources/Viewport/DefaultViewportInteractor.cpp OrthancStone/Sources/Viewport/DefaultViewportInteractor.h OrthancStone/Sources/Viewport/IViewportInteractor.h
diffstat 6 files changed, 157 insertions(+), 102 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Tue Oct 06 17:29:57 2026 +0200
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Tue Oct 06 18:13:47 2026 +0200
@@ -3893,6 +3893,40 @@
   class Interactor : public OrthancStone::DefaultViewportInteractor
   {
   private:
+    class GrayscaleObserver : public OrthancStone::GrayscaleWindowingSceneTracker::IObserver
+    {
+    private:
+      ViewerViewport&  viewer_;
+
+    public:
+      GrayscaleObserver(ViewerViewport& viewer) :
+        viewer_(viewer)
+      {
+      }
+
+      virtual void HandleGrayscaleWindowingChange(const OrthancStone::Windowing& windowing) ORTHANC_OVERRIDE
+      {
+        viewer_.UpdateWindowing(WindowingState_User, windowing);
+      }
+    };
+
+    class GrayscaleFactory : public OrthancStone::GrayscaleWindowingSceneTracker::IObserverFactory
+    {
+    private:
+      ViewerViewport&  viewer_;
+
+    public:
+      GrayscaleFactory(ViewerViewport& viewer) :
+        viewer_(viewer)
+      {
+      }
+
+      virtual OrthancStone::GrayscaleWindowingSceneTracker::IObserver* Create() ORTHANC_OVERRIDE
+      {
+        return new GrayscaleObserver(viewer_);
+      }
+    };
+
     ViewerViewport&  viewer_;
     WebViewerAction  leftAction_;
     WebViewerAction  middleAction_;
@@ -3930,6 +3964,7 @@
       SetLeftButtonAction(ConvertWebViewerAction(leftAction));
       SetMiddleButtonAction(ConvertWebViewerAction(middleAction));
       SetRightButtonAction(ConvertWebViewerAction(rightAction));
+      SetGrayscaleWindowingObserverFactory(new GrayscaleFactory(viewer));
     }
 
     virtual OrthancStone::IFlexiblePointerTracker* CreateTracker(
--- a/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.cpp	Tue Oct 06 17:29:57 2026 +0200
+++ b/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.cpp	Tue Oct 06 18:13:47 2026 +0200
@@ -35,26 +35,19 @@
     class GrayscaleLayerAccessor : public boost::noncopyable
     {
     private:
-      std::unique_ptr<IViewport::ILock>   lock_;
-      FloatTextureSceneLayer*             layer_;
+      FloatTextureSceneLayer*  layer_;
 
     public:
-      GrayscaleLayerAccessor(boost::weak_ptr<IViewport> viewportWeak,
+      GrayscaleLayerAccessor(Scene2D& scene,
                              int layerIndex) :
         layer_(NULL)
       {
-        boost::shared_ptr<IViewport> viewport = viewportWeak.lock();
-        if (viewport != NULL)
+        if (scene.HasLayer(layerIndex))
         {
-          lock_.reset(viewport->Lock());
-
-          if (lock_->GetController().GetScene().HasLayer(layerIndex))
+          ISceneLayer& layer = scene.GetLayer(layerIndex);
+          if (layer.GetType() == ISceneLayer::Type_FloatTexture)
           {
-            ISceneLayer& layer = lock_->GetController().GetScene().GetLayer(layerIndex);
-            if (layer.GetType() == ISceneLayer::Type_FloatTexture)
-            {
-              layer_ = &dynamic_cast<FloatTextureSceneLayer&>(layer);
-            }
+            layer_ = &dynamic_cast<FloatTextureSceneLayer&>(layer);
           }
         }
       }
@@ -75,39 +68,26 @@
           return *layer_;
         }
       }
-
-      void Invalidate()
-      {
-        if (lock_.get() != NULL)
-        {
-          lock_->Invalidate();
-        }
-      }
-
-      void BroadcastGrayscaleWindowingChanged(double center,
-                                              double width)
-      {
-        if (lock_.get() != NULL)
-        {
-          lock_->GetController().BroadcastGrayscaleWindowingChanged(Windowing(center, width));
-        }
-      }        
     };
   }
   
-  bool GrayscaleWindowingSceneTracker::SetWindowing(float center,
+  bool GrayscaleWindowingSceneTracker::SetWindowing(Scene2D& scene,
+                                                    float center,
                                                     float width)
   {
     if (active_)
     {
-      boost::shared_ptr<IViewport> viewport = viewport_.lock();
-      GrayscaleLayerAccessor accessor(viewport, layerIndex_);
+      GrayscaleLayerAccessor accessor(scene, layerIndex_);
       
       if (accessor.IsValid())
       {
         accessor.GetLayer().SetCustomWindowing(center, width);
-        accessor.BroadcastGrayscaleWindowingChanged(center, width);
-        accessor.Invalidate();
+
+        if (observer_.get() != NULL)
+        {
+          observer_->HandleGrayscaleWindowingChange(Windowing(center, width));
+        }
+
         return true;
       }
     }
@@ -116,12 +96,11 @@
   }
     
 
-  GrayscaleWindowingSceneTracker::GrayscaleWindowingSceneTracker(boost::weak_ptr<IViewport> viewport,
+  GrayscaleWindowingSceneTracker::GrayscaleWindowingSceneTracker(Scene2D& scene,
                                                                  int layerIndex,
                                                                  const PointerEvent& event,
                                                                  unsigned int canvasWidth,
                                                                  unsigned int canvasHeight) :
-    viewport_(viewport),
     layerIndex_(layerIndex),
     clickX_(event.GetMainPosition().GetX()),
     clickY_(event.GetMainPosition().GetY())
@@ -131,31 +110,36 @@
     if (canvasWidth > 3 &&
         canvasHeight > 3)
     {
-      boost::shared_ptr<IViewport> locked = viewport_.lock();
+      GrayscaleLayerAccessor accessor(scene, layerIndex_);
 
-      if (locked)
+      if (accessor.IsValid())
       {
-        GrayscaleLayerAccessor accessor(locked, layerIndex_);
-      
-        if (accessor.IsValid())
-        {
-          FloatTextureSceneLayer& layer = accessor.GetLayer();
+        accessor.GetLayer().GetWindowing(originalCenter_, originalWidth_);
         
-          layer.GetWindowing(originalCenter_, originalWidth_);
+        float minValue, maxValue;
+        accessor.GetLayer().GetRange(minValue, maxValue);
         
-          float minValue, maxValue;
-          layer.GetRange(minValue, maxValue);
-        
-          normalization_ = (maxValue - minValue) / static_cast<double>(std::min(canvasWidth, canvasHeight) - 1);
-          active_ = true;
-        }
-        else
-        {
-          LOG(INFO) << "Cannot create GrayscaleWindowingSceneTracker on a non-float texture";
-        }
+        normalization_ = (maxValue - minValue) / static_cast<double>(std::min(canvasWidth, canvasHeight) - 1);
+        active_ = true;
+      }
+      else
+      {
+        LOG(INFO) << "Cannot create GrayscaleWindowingSceneTracker on a non-float texture";
       }
     }
   }
+
+  void GrayscaleWindowingSceneTracker::SetObserver(IObserver* observer)
+  {
+    if (observer == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+    else
+    {
+      observer_.reset(observer);
+    }
+  }
   
   bool GrayscaleWindowingSceneTracker::PointerMove(const PointerEvent& event,
                                                    Scene2D& scene)
@@ -173,7 +157,7 @@
         width = 1;
       }
       
-      return SetWindowing(center, width);
+      return SetWindowing(scene, center, width);
     }
     else
     {
@@ -183,6 +167,6 @@
 
   void GrayscaleWindowingSceneTracker::Cancel(Scene2D& scene)
   {
-    SetWindowing(originalCenter_, originalWidth_);
+    SetWindowing(scene, originalCenter_, originalWidth_);
   }
 }
--- a/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.h	Tue Oct 06 17:29:57 2026 +0200
+++ b/OrthancStone/Sources/Scene2D/GrayscaleWindowingSceneTracker.h	Tue Oct 06 18:13:47 2026 +0200
@@ -24,17 +24,36 @@
 #pragma once
 
 #include "../Scene2DViewport/OneGesturePointerTracker.h"
+#include "../Toolbox/Windowing.h"
 #include "../Viewport/IViewport.h"
 
-#include <boost/weak_ptr.hpp>
 
 namespace OrthancStone
 {
   class GrayscaleWindowingSceneTracker : public OneGesturePointerTracker
   {
+  public:
+    class IObserver : public boost::noncopyable
+    {
+    public:
+      virtual ~IObserver()
+      {
+      }
+
+      virtual void HandleGrayscaleWindowingChange(const Windowing& windowing) = 0;
+    };
+
+    class IObserverFactory : public boost::noncopyable
+    {
+    public:
+      virtual ~IObserverFactory()
+      {
+      }
+
+      virtual IObserver* Create() = 0;
+    };
+
   private:
-    boost::weak_ptr<IViewport> viewport_;
-    
     bool    active_;
     int     layerIndex_;
     double  normalization_;
@@ -43,16 +62,21 @@
     double  clickX_;
     double  clickY_;
 
-    bool SetWindowing(float center,
+    std::unique_ptr<IObserver>  observer_;
+
+    bool SetWindowing(Scene2D& scene,
+                      float center,
                       float width);
     
   public:
-    GrayscaleWindowingSceneTracker(boost::weak_ptr<IViewport> viewport,
+    GrayscaleWindowingSceneTracker(Scene2D& scene,
                                    int layerIndex,
                                    const PointerEvent& event,
                                    unsigned int canvasWidth,
                                    unsigned int canvasHeight);
 
+    void SetObserver(IObserver* observer /* takes ownership */);
+
     virtual bool PointerMove(const PointerEvent& event,
                              Scene2D& scene) ORTHANC_OVERRIDE;
     
--- a/OrthancStone/Sources/Viewport/DefaultViewportInteractor.cpp	Tue Oct 06 17:29:57 2026 +0200
+++ b/OrthancStone/Sources/Viewport/DefaultViewportInteractor.cpp	Tue Oct 06 18:13:47 2026 +0200
@@ -35,12 +35,11 @@
 
 namespace OrthancStone
 {
-  IFlexiblePointerTracker* DefaultViewportInteractor::CreateTrackerInternal(
-    const boost::shared_ptr<IViewport>& viewport,   // TODO Refactoring - Should be Scene2D&
-    MouseAction action,
-    const PointerEvent& event,
-    unsigned int viewportWidth,
-    unsigned int viewportHeight)
+  IFlexiblePointerTracker* DefaultViewportInteractor::CreateTrackerInternal(Scene2D& scene,
+                                                                            MouseAction action,
+                                                                            const PointerEvent& event,
+                                                                            unsigned int viewportWidth,
+                                                                            unsigned int viewportHeight)
   {
     switch (action)
     {
@@ -48,51 +47,38 @@
         return NULL;
 
       case MouseAction_Rotate:
-      {
-        std::unique_ptr<IViewport::ILock> lock(viewport->Lock());
-        return new RotateSceneTracker(lock->GetController().GetScene(), event);
-      }
+        return new RotateSceneTracker(scene, event);
 
       case MouseAction_GrayscaleWindowing:
       {
-        if (!viewport)
+        if (scene.HasLayer(windowingLayer_) &&
+            scene.GetLayer(windowingLayer_).GetType() == ISceneLayer::Type_FloatTexture)
         {
-          return NULL;
+          std::unique_ptr<GrayscaleWindowingSceneTracker> tracker(
+            new GrayscaleWindowingSceneTracker(scene, windowingLayer_, event, viewportWidth, viewportHeight));
+
+          if (grayscaleFactory_.get() != NULL)
+          {
+            tracker->SetObserver(grayscaleFactory_->Create());
+          }
+
+          return tracker.release();
         }
         else
         {
-          std::unique_ptr<IViewport::ILock> lock(viewport->Lock());
-          if (lock->GetController().GetScene().HasLayer(windowingLayer_) &&
-              lock->GetController().GetScene().GetLayer(windowingLayer_).GetType() == ISceneLayer::Type_FloatTexture)
-          {
-            return new GrayscaleWindowingSceneTracker(
-              viewport, windowingLayer_, event, viewportWidth, viewportHeight);
-          }
-          else
-          {
-            // Don't create the tracker if the layer is not a float texture
-            return NULL;
-          }
+          // Don't create the tracker if the layer is not a float texture
+          return NULL;
         }
       }
 
       case MouseAction_Pan:
-      {
-        std::unique_ptr<IViewport::ILock> lock(viewport->Lock());
-        return new PanSceneTracker(lock->GetController().GetScene(), event);
-      }
+        return new PanSceneTracker(scene, event);
       
       case MouseAction_Zoom:
-      {
-        std::unique_ptr<IViewport::ILock> lock(viewport->Lock());
-        return new ZoomSceneTracker(lock->GetController().GetScene(), event, viewportHeight);
-      }
+        return new ZoomSceneTracker(scene, event, viewportHeight);
       
       case MouseAction_MagnifyingGlass:
-      {
-        std::unique_ptr<IViewport::ILock> lock(viewport->Lock());
-        return new MagnifyingGlassTracker(lock->GetController().GetScene(), event);
-      }
+        return new MagnifyingGlassTracker(scene, event);
 
       default:
         throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
@@ -106,6 +92,11 @@
     unsigned int                viewportWidth,
     unsigned int                viewportHeight)
   {
+    if (!viewport)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
     MouseAction action;
     
     switch (event.GetMouseButton())
@@ -137,7 +128,10 @@
         return NULL;
     }
 
-    return CreateTrackerInternal(viewport, action, event, viewportWidth, viewportHeight);
+    {
+      std::unique_ptr<IViewport::ILock> lock(viewport->Lock());
+      return CreateTrackerInternal(lock->GetController().GetScene(), action, event, viewportWidth, viewportHeight);
+    }
   }
 
 
@@ -147,4 +141,17 @@
     // "HasMouseOver()" returns "false"
     throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
   }
+
+
+  void DefaultViewportInteractor::SetGrayscaleWindowingObserverFactory(GrayscaleWindowingSceneTracker::IObserverFactory* factory)
+  {
+    if (factory == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+    else
+    {
+      grayscaleFactory_.reset(factory);
+    }
+  }
 }
--- a/OrthancStone/Sources/Viewport/DefaultViewportInteractor.h	Tue Oct 06 17:29:57 2026 +0200
+++ b/OrthancStone/Sources/Viewport/DefaultViewportInteractor.h	Tue Oct 06 18:13:47 2026 +0200
@@ -22,6 +22,7 @@
 
 #pragma once
 
+#include "../Scene2D/GrayscaleWindowingSceneTracker.h"
 #include "IViewportInteractor.h"
 
 #include <Compatibility.h>  // For ORTHANC_OVERRIDE
@@ -37,7 +38,9 @@
     MouseAction  middleButtonAction_;
     MouseAction  rightButtonAction_;
 
-    IFlexiblePointerTracker* CreateTrackerInternal(const boost::shared_ptr<IViewport>& viewport,
+    std::unique_ptr<GrayscaleWindowingSceneTracker::IObserverFactory>  grayscaleFactory_;
+
+    IFlexiblePointerTracker* CreateTrackerInternal(Scene2D& scene,
                                                    MouseAction action,
                                                    const PointerEvent& event,
                                                    unsigned int viewportWidth,
@@ -91,7 +94,7 @@
     {
       rightButtonAction_ = action;
     }
-    
+
     virtual IFlexiblePointerTracker* CreateTracker(const boost::shared_ptr<IViewport>& viewport,
                                                    const PointerEvent& event,
                                                    unsigned int viewportWidth,
@@ -104,5 +107,7 @@
 
     virtual void HandleMouseHover(IViewport::ILock& viewportLock,
                                   const PointerEvent& event) ORTHANC_OVERRIDE;
+
+    void SetGrayscaleWindowingObserverFactory(GrayscaleWindowingSceneTracker::IObserverFactory* factory /* takes ownership */);
   };
 }
--- a/OrthancStone/Sources/Viewport/IViewportInteractor.h	Tue Oct 06 17:29:57 2026 +0200
+++ b/OrthancStone/Sources/Viewport/IViewportInteractor.h	Tue Oct 06 18:13:47 2026 +0200
@@ -42,6 +42,6 @@
     virtual bool HasMouseHover() const = 0;
 
     virtual void HandleMouseHover(IViewport::ILock& viewportLock,
-                                  const PointerEvent& event) = 0;
+                                  const PointerEvent& event) = 0;  // TODO Refactoring - Should return "true" to invalidate
   };
 }