# HG changeset patch # User Sebastien Jodogne # Date 1575395463 -3600 # Node ID 00e6bff9ea3978146b8ebcb30cffb2e16ed89126 # Parent 17a92c39c633f70b33881965e150c263b0ddc31c handling of mouse interactions in ViewportController diff -r 17a92c39c633 -r 00e6bff9ea39 Framework/Scene2D/PointerEvent.cpp --- a/Framework/Scene2D/PointerEvent.cpp Tue Dec 03 12:29:06 2019 +0100 +++ b/Framework/Scene2D/PointerEvent.cpp Tue Dec 03 18:51:03 2019 +0100 @@ -26,6 +26,7 @@ namespace OrthancStone { PointerEvent::PointerEvent() : + button_(MouseButton_None), hasAltModifier_(false), hasControlModifier_(false), hasShiftModifier_(false) diff -r 17a92c39c633 -r 00e6bff9ea39 Framework/Scene2D/PointerEvent.h --- a/Framework/Scene2D/PointerEvent.h Tue Dec 03 12:29:06 2019 +0100 +++ b/Framework/Scene2D/PointerEvent.h Tue Dec 03 18:51:03 2019 +0100 @@ -31,6 +31,7 @@ class PointerEvent : public boost::noncopyable { private: + MouseButton button_; std::vector positions_; bool hasAltModifier_; bool hasControlModifier_; @@ -88,5 +89,15 @@ { return hasShiftModifier_; } + + void SetMouseButton(MouseButton button) + { + button_ = button; + } + + MouseButton GetMouseButton() const + { + return button_; + } }; } diff -r 17a92c39c633 -r 00e6bff9ea39 Framework/Scene2DViewport/ViewportController.cpp --- a/Framework/Scene2DViewport/ViewportController.cpp Tue Dec 03 12:29:06 2019 +0100 +++ b/Framework/Scene2DViewport/ViewportController.cpp Tue Dec 03 18:51:03 2019 +0100 @@ -24,39 +24,75 @@ #include "MeasureCommands.h" #include "../StoneException.h" +#include "../Scene2D/PanSceneTracker.h" +#include "../Scene2D/RotateSceneTracker.h" +#include "../Scene2D/ZoomSceneTracker.h" #include namespace OrthancStone { + IFlexiblePointerTracker* DefaultViewportInteractor::CreateTracker(boost::shared_ptr controller, + const PointerEvent& event) + { + switch (event.GetMouseButton()) + { + case MouseButton_Left: + return new RotateSceneTracker(controller, event); + + case MouseButton_Middle: + return new PanSceneTracker(controller, event); + + case MouseButton_Right: + { + std::auto_ptr lock(controller->GetViewport().Lock()); + if (lock->HasCompositor()) + { + return new ZoomSceneTracker(controller, event, lock->GetCompositor().GetCanvasWidth()); + } + else + { + return NULL; + } + } + + default: + return NULL; + } + } + + ViewportController::ViewportController(boost::weak_ptr undoStackW, - IViewport& viewport) + boost::shared_ptr viewport) : undoStackW_(undoStackW) - , canvasToSceneFactor_(0.0) , viewport_(viewport) + , canvasToSceneFactor_(1) { + if (viewport.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + interactor_.reset(new DefaultViewportInteractor); } ViewportController::~ViewportController() { - } - boost::shared_ptr ViewportController::GetUndoStack() + void ViewportController::SetInteractor(boost::shared_ptr interactor) { - return undoStackW_.lock(); - } - - boost::shared_ptr ViewportController::GetUndoStack() const - { - return undoStackW_.lock(); + activeTracker_.reset(); + interactor_ = interactor; } void ViewportController::PushCommand(boost::shared_ptr command) { boost::shared_ptr undoStack = undoStackW_.lock(); - if(undoStack.get() != NULL) + if (undoStack.get() != NULL) + { undoStack->PushCommand(command); + } else { LOG(ERROR) << "Internal error: no undo stack in the viewport controller!"; @@ -67,7 +103,9 @@ { boost::shared_ptr undoStack = undoStackW_.lock(); if (undoStack.get() != NULL) + { undoStack->Undo(); + } else { LOG(ERROR) << "Internal error: no undo stack in the viewport controller!"; @@ -78,7 +116,9 @@ { boost::shared_ptr undoStack = undoStackW_.lock(); if (undoStack.get() != NULL) + { undoStack->Redo(); + } else { LOG(ERROR) << "Internal error: no undo stack in the viewport controller!"; @@ -89,7 +129,9 @@ { boost::shared_ptr undoStack = undoStackW_.lock(); if (undoStack.get() != NULL) + { return undoStack->CanUndo(); + } else { LOG(ERROR) << "Internal error: no undo stack in the viewport controller!"; @@ -101,7 +143,9 @@ { boost::shared_ptr undoStack = undoStackW_.lock(); if (undoStack.get() != NULL) + { return undoStack->CanRedo(); + } else { LOG(ERROR) << "Internal error: no undo stack in the viewport controller!"; @@ -109,11 +153,6 @@ } } - bool ViewportController::HandlePointerEvent(PointerEvent e) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - std::vector > ViewportController::HitTestMeasureTools( ScenePoint2D p) { @@ -138,37 +177,22 @@ OrthancStone::AffineTransform2D ViewportController::GetCanvasToSceneTransform() const { - std::auto_ptr lock(viewport_.Lock()); + std::auto_ptr lock(viewport_->Lock()); return lock->GetScene().GetCanvasToSceneTransform(); } OrthancStone::AffineTransform2D ViewportController::GetSceneToCanvasTransform() const { - std::auto_ptr lock(viewport_.Lock()); + std::auto_ptr lock(viewport_->Lock()); return lock->GetScene().GetSceneToCanvasTransform(); } - void ViewportController::SetSceneToCanvasTransform( - const AffineTransform2D& transform) + void ViewportController::SetSceneToCanvasTransform(const AffineTransform2D& transform) { { - std::auto_ptr lock(viewport_.Lock()); + std::auto_ptr lock(viewport_->Lock()); lock->GetScene().SetSceneToCanvasTransform(transform); - } - - BroadcastMessage(SceneTransformChanged(*this)); - - // update the canvas to scene factor - canvasToSceneFactor_ = 0.0; - canvasToSceneFactor_ = GetCanvasToSceneFactor(); - } - - void ViewportController::FitContent( - unsigned int canvasWidth, unsigned int canvasHeight) - { - { - std::auto_ptr lock(viewport_.Lock()); - lock->GetScene().FitContent(canvasWidth, canvasHeight); + canvasToSceneFactor_ = lock->GetScene().GetCanvasToSceneTransform().ComputeZoom(); } BroadcastMessage(SceneTransformChanged(*this)); @@ -176,14 +200,13 @@ void ViewportController::FitContent() { - std::auto_ptr lock(viewport_.Lock()); + { + std::auto_ptr lock(viewport_->Lock()); + lock->FitContent(); + canvasToSceneFactor_ = lock->GetScene().GetCanvasToSceneTransform().ComputeZoom(); + } - if (lock->HasCompositor()) - { - const ICompositor& compositor = lock->GetCompositor(); - lock->GetScene().FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight()); - BroadcastMessage(SceneTransformChanged(*this)); - } + BroadcastMessage(SceneTransformChanged(*this)); } void ViewportController::AddMeasureTool(boost::shared_ptr measureTool) @@ -202,14 +225,8 @@ measureTools_.end()); } - double ViewportController::GetCanvasToSceneFactor() const { - if (canvasToSceneFactor_ == 0) - { - std::auto_ptr lock(viewport_.Lock()); - canvasToSceneFactor_ = lock->GetScene().GetCanvasToSceneTransform().ComputeZoom(); - } return canvasToSceneFactor_; } @@ -232,4 +249,62 @@ { return TEXT_CENTER_DISTANCE_CANVAS_COORD * GetCanvasToSceneFactor(); } + + + void ViewportController::HandleMousePress(const PointerEvent& event) + { + if (activeTracker_) + { + // We are dealing with a multi-stage tracker (that is made of several interactions) + activeTracker_->PointerDown(event); + + if (!activeTracker_->IsAlive()) + { + activeTracker_.reset(); + } + } + else + { + // Check whether there is already a measure tool at that position + for (size_t i = 0; i < measureTools_.size(); ++i) + { + if (measureTools_[i]->HitTest(event.GetMainPosition())) + { + activeTracker_ = measureTools_[i]->CreateEditionTracker(event); + return; + } + } + + // No measure tool, create new tracker from the interactor + if (interactor_) + { + activeTracker_.reset(interactor_->CreateTracker(shared_from_this(), event)); + } + else + { + activeTracker_.reset(); + } + } + } + + void ViewportController::HandleMouseMove(const PointerEvent& event) + { + if (activeTracker_) + { + activeTracker_->PointerMove(event); + } + } + + void ViewportController::HandleMouseRelease(const PointerEvent& event) + { + if (activeTracker_) + { + activeTracker_->PointerUp(event); + + if (!activeTracker_->IsAlive()) + { + activeTracker_.reset(); + } + } + } } diff -r 17a92c39c633 -r 00e6bff9ea39 Framework/Scene2DViewport/ViewportController.h --- a/Framework/Scene2DViewport/ViewportController.h Tue Dec 03 12:29:06 2019 +0100 +++ b/Framework/Scene2DViewport/ViewportController.h Tue Dec 03 18:51:03 2019 +0100 @@ -23,13 +23,35 @@ #include "PredeclaredTypes.h" #include "../Viewport/IViewport.h" -#include "../Scene2D/PointerEvent.h" #include "../Scene2DViewport/IFlexiblePointerTracker.h" +#include #include namespace OrthancStone { + // TODO - Move this to another file + class IViewportInteractor : public boost::noncopyable + { + public: + virtual ~IViewportInteractor() + { + } + + virtual IFlexiblePointerTracker* CreateTracker(boost::shared_ptr controller, + const PointerEvent& event) = 0; + }; + + + // TODO - Move this to another file + class DefaultViewportInteractor : public IViewportInteractor + { + public: + virtual IFlexiblePointerTracker* CreateTracker(boost::shared_ptr controller, + const PointerEvent& event) ORTHANC_OVERRIDE; + }; + + class UndoStack; const double ARC_RADIUS_CANVAS_COORD = 30.0; @@ -74,23 +96,20 @@ Each canvas or other GUI area where we want to display a 2D image, either directly or through slicing must be assigned a ViewportController. */ - class ViewportController : public IObservable + class ViewportController : + public IObservable, + public boost::enable_shared_from_this { public: ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, \ - SceneTransformChanged, ViewportController); + SceneTransformChanged, ViewportController); ViewportController(boost::weak_ptr undoStackW, - IViewport& viewport); - + boost::shared_ptr viewport); ~ViewportController(); - /** - This method is called by the GUI system and should update/delete the - current tracker - */ - bool HandlePointerEvent(PointerEvent e); + void SetInteractor(boost::shared_ptr interactor); /** This method returns the list of measure tools containing the supplied point @@ -109,7 +128,7 @@ With this method, the object takes ownership of the supplied tracker and updates it according to user interaction */ - void SetActiveTracker(boost::shared_ptr tracker); + void AcquireActiveTracker(IFlexiblePointerTracker* tracker); /** Forwarded to the underlying scene */ AffineTransform2D GetCanvasToSceneTransform() const; @@ -121,7 +140,6 @@ void SetSceneToCanvasTransform(const AffineTransform2D& transform); /** Forwarded to the underlying scene, and broadcasted to the observers */ - void FitContent(unsigned int canvasWidth, unsigned int canvasHeight); void FitContent(); /** Adds a new measure tool */ @@ -174,24 +192,29 @@ IViewport& GetViewport() const { - return viewport_; + return *viewport_; } + + // Must be expressed in canvas coordinates + void HandleMousePress(const PointerEvent& event); + + // Must be expressed in canvas coordinates + void HandleMouseMove(const PointerEvent& event); + + // Must be expressed in canvas coordinates + void HandleMouseRelease(const PointerEvent& event); + private: double GetCanvasToSceneFactor() const; - boost::weak_ptr undoStackW_; - - boost::shared_ptr GetUndoStack(); - boost::shared_ptr GetUndoStack() const; - - std::vector > measureTools_; - boost::shared_ptr tracker_; + boost::weak_ptr undoStackW_; // Global stack, possibly shared by all viewports + boost::shared_ptr viewport_; + boost::shared_ptr interactor_; // Application-specific factory of trackers + std::vector > measureTools_; + boost::shared_ptr activeTracker_; // TODO - Can't this be a "std::auto_ptr"? // this is cached - mutable double canvasToSceneFactor_; - - // Refactoring on 2019-07-10: Removing shared_ptr from scene - IViewport& viewport_; + double canvasToSceneFactor_; }; } diff -r 17a92c39c633 -r 00e6bff9ea39 Framework/StoneEnumerations.h --- a/Framework/StoneEnumerations.h Tue Dec 03 12:29:06 2019 +0100 +++ b/Framework/StoneEnumerations.h Tue Dec 03 18:51:03 2019 +0100 @@ -59,7 +59,8 @@ { MouseButton_Left, MouseButton_Right, - MouseButton_Middle + MouseButton_Middle, + MouseButton_None // For instance, because of touch event }; enum MouseWheelDirection diff -r 17a92c39c633 -r 00e6bff9ea39 Framework/Viewport/IViewport.h --- a/Framework/Viewport/IViewport.h Tue Dec 03 12:29:06 2019 +0100 +++ b/Framework/Viewport/IViewport.h Tue Dec 03 18:51:03 2019 +0100 @@ -49,6 +49,7 @@ virtual Scene2D& GetScene() = 0; + // Get the center of the given pixel, in canvas coordinates virtual ScenePoint2D GetPixelCenterCoordinates(int x, int y) = 0; virtual bool HasCompositor() const = 0;