# HG changeset patch # User Sebastien Jodogne # Date 1667397395 -3600 # Node ID e943a84da9ac14a2c577886165398756b5b7e826 # Parent 3e9ced39cd1b6db928774f034954e7a4ada5c61a creation of text annotations diff -r 3e9ced39cd1b -r e943a84da9ac Applications/StoneWebViewer/NEWS --- a/Applications/StoneWebViewer/NEWS Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/NEWS Wed Nov 02 14:56:35 2022 +0100 @@ -2,6 +2,7 @@ =============================== * New types of annotations: + - Text annotation - Pixel probe - Rectangle probe - Ellipse probe diff -r 3e9ced39cd1b -r e943a84da9ac Applications/StoneWebViewer/WebApplication/app.js --- a/Applications/StoneWebViewer/WebApplication/app.js Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/WebApplication/app.js Wed Nov 02 14:56:35 2022 +0100 @@ -1188,6 +1188,15 @@ window.addEventListener('StoneAnnotationRemoved', function() { // Ignore }); + + window.addEventListener('TextAnnotationRequired', function(args) { + var label = prompt('Enter your annotation:', ''); + if (label !== null) { + stone.AddTextAnnotation(args.detail.canvasId, label, + args.detail.pointedX, args.detail.pointedY, + args.detail.labelX, args.detail.labelY); + } + }); } }); diff -r 3e9ced39cd1b -r e943a84da9ac Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py --- a/Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py Wed Nov 02 14:56:35 2022 +0100 @@ -174,6 +174,8 @@ arg['type'] = "'int'" elif argType == 'const char *': arg['type'] = "'string'" + elif argType == 'double': + arg['type'] = "'double'" else: raise Exception('Unknown type for argument "%s" in function "%s()": %s' % (child.displayname, node.spelling, argType)) diff -r 3e9ced39cd1b -r e943a84da9ac Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp --- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Nov 02 14:56:35 2022 +0100 @@ -1597,6 +1597,10 @@ virtual void SignalStoneAnnotationAdded(const ViewerViewport& viewport) = 0; virtual void SignalStoneAnnotationRemoved(const ViewerViewport& viewport) = 0; + + virtual void SignalStoneTextAnnotationRequired(const ViewerViewport& viewport, + const OrthancStone::ScenePoint2D& pointedPosition, + const OrthancStone::ScenePoint2D& labelPosition) = 0; }; private: @@ -2692,6 +2696,14 @@ } } + void Handle(const OrthancStone::AnnotationsSceneLayer::TextAnnotationRequiredMessage& message) + { + if (observer_.get() != NULL) + { + observer_->SignalStoneTextAnnotationRequired(*this, message.GetPointedPosition(), message.GetLabelPosition()); + } + } + public: virtual ~ViewerViewport() { @@ -2732,6 +2744,9 @@ viewport->Register( *viewport->stoneAnnotations_, &ViewerViewport::Handle); + + viewport->Register( + *viewport->stoneAnnotations_, &ViewerViewport::Handle); } { @@ -3435,6 +3450,14 @@ Redraw(); } } + + void AddTextAnnotation(const std::string& label, + const OrthancStone::ScenePoint2D& pointedPosition, + const OrthancStone::ScenePoint2D& labelPosition) + { + stoneAnnotations_->AddTextAnnotation(label, pointedPosition, labelPosition); + Redraw(); + } }; @@ -3695,6 +3718,27 @@ }, viewport.GetCanvasId().c_str()); } + + virtual void SignalStoneTextAnnotationRequired(const ViewerViewport& viewport, + const OrthancStone::ScenePoint2D& pointedPosition, + const OrthancStone::ScenePoint2D& labelPosition) ORTHANC_OVERRIDE + { + EM_ASM({ + const customEvent = document.createEvent("CustomEvent"); + customEvent.initCustomEvent("TextAnnotationRequired", false, false, + { "canvasId" : UTF8ToString($0), + "pointedX" : $1, + "pointedY" : $2, + "labelX" : $3, + "labelY" : $4 }); + window.dispatchEvent(customEvent); + }, + viewport.GetCanvasId().c_str(), + pointedPosition.GetX(), + pointedPosition.GetY(), + labelPosition.GetX(), + labelPosition.GetY() ); + } }; @@ -4497,4 +4541,21 @@ EXTERN_CATCH_EXCEPTIONS; return false; } + + + EMSCRIPTEN_KEEPALIVE + void AddTextAnnotation(const char* canvas, + const char* label, + double pointedX, + double pointedY, + double labelX, + double labelY) + { + try + { + GetViewport(canvas)->AddTextAnnotation(label, OrthancStone::ScenePoint2D(pointedX, pointedY), + OrthancStone::ScenePoint2D(labelX, labelY)); + } + EXTERN_CATCH_EXCEPTIONS; + } } diff -r 3e9ced39cd1b -r e943a84da9ac OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp --- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Nov 02 13:52:14 2022 +0100 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Nov 02 14:56:35 2022 +0100 @@ -1272,14 +1272,25 @@ public: TextAnnotation(AnnotationsSceneLayer& that, const std::string& label, - const ScenePoint2D& p1, - const ScenePoint2D& p2) : - SegmentAnnotation(that, Handle::Shape_Invisible, p1, Handle::Shape_Square, p2) + const ScenePoint2D& pointedPosition, + const ScenePoint2D& labelPosition) : + SegmentAnnotation(that, Handle::Shape_Invisible, pointedPosition /* p1 */, + Handle::Shape_Square, labelPosition /* p2 */) { SetStartArrow(true); UpdateLabel(label); } + ScenePoint2D GetPointedPosition() const + { + return GetHandle1().GetCenter(); + } + + ScenePoint2D GetLabelPosition() const + { + return GetHandle2().GetCenter(); + } + void UpdateLabel(const std::string& label) { TextSceneLayer content; @@ -2325,6 +2336,25 @@ AnnotationsSceneLayer& layer_; Annotation* annotation_; AffineTransform2D canvasToScene_; + + protected: + AnnotationsSceneLayer& GetLayer() const + { + return layer_; + } + + const Annotation& GetAnnotation() const + { + if (IsAlive()) + { + assert(annotation_ != NULL); + return *annotation_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } public: CreateTwoHandlesTracker(Annotation& annotation, @@ -2506,6 +2536,35 @@ }; + class AnnotationsSceneLayer::CreateTextAnnotationTracker : public CreateTwoHandlesTracker + { + public: + CreateTextAnnotationTracker(AnnotationsSceneLayer& that, + const std::string& label, + const ScenePoint2D& position, + const AffineTransform2D& canvasToScene) : + CreateTwoHandlesTracker(*new TextAnnotation(that, label, position, position), canvasToScene) + { + } + + virtual void PointerUp(const PointerEvent& event, + const Scene2D& scene) ORTHANC_OVERRIDE + { + std::unique_ptr request; + + { + const TextAnnotation& annotation = dynamic_cast(GetAnnotation()); + request.reset(new TextAnnotationRequiredMessage(GetLayer(), annotation.GetPointedPosition(), annotation.GetLabelPosition())); + } + + Cancel(scene); // Warning: "annotation_" is now invalid! + + GetLayer().BroadcastMessage(AnnotationChangedMessage(GetLayer())); + GetLayer().BroadcastMessage(*request); + } + }; + + // Dummy tracker that is only used for deletion, in order to warn // the caller that the mouse action was taken into consideration class AnnotationsSceneLayer::RemoveTracker : public IFlexiblePointerTracker @@ -2616,6 +2675,7 @@ const ScenePoint2D& p2) { annotations_.insert(new LengthAnnotation(*this, units_, true /* show label */, p1, p2)); + BroadcastMessage(AnnotationChangedMessage(*this)); } @@ -2623,6 +2683,7 @@ const ScenePoint2D& p2) { annotations_.insert(new CircleAnnotation(*this, units_, p1, p2)); + BroadcastMessage(AnnotationChangedMessage(*this)); } @@ -2631,6 +2692,7 @@ const ScenePoint2D& p3) { annotations_.insert(new AngleAnnotation(*this, p1, p2, p3)); + BroadcastMessage(AnnotationChangedMessage(*this)); } @@ -2810,10 +2872,7 @@ } case Tool_TextAnnotation: - { - Annotation* annotation = new TextAnnotation(*this, "" /* empty label */, s, s); - return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); - } + return new CreateTextAnnotationTracker(*this, "" /* empty label */, s, scene.GetCanvasToSceneTransform()); default: return NULL; @@ -2930,4 +2989,13 @@ } } } + + + void AnnotationsSceneLayer::AddTextAnnotation(const std::string& label, + const ScenePoint2D& pointedPosition, + const ScenePoint2D& labelPosition) + { + annotations_.insert(new TextAnnotation(*this, label, pointedPosition, labelPosition)); + BroadcastMessage(AnnotationChangedMessage(*this)); + } } diff -r 3e9ced39cd1b -r e943a84da9ac OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h --- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Nov 02 13:52:14 2022 +0100 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Nov 02 14:56:35 2022 +0100 @@ -34,6 +34,35 @@ ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, AnnotationRemovedMessage, AnnotationsSceneLayer); ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, AnnotationChangedMessage, AnnotationsSceneLayer); + class TextAnnotationRequiredMessage : public OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + ScenePoint2D pointedPosition_; + ScenePoint2D labelPosition_; + + public: + TextAnnotationRequiredMessage(const AnnotationsSceneLayer& origin, + ScenePoint2D pointedPosition, + ScenePoint2D labelPosition) : + OriginMessage(origin), + pointedPosition_(pointedPosition), + labelPosition_(labelPosition) + { + } + + const ScenePoint2D& GetPointedPosition() const + { + return pointedPosition_; + } + + const ScenePoint2D& GetLabelPosition() const + { + return labelPosition_; + } + }; + enum Tool { Tool_Edit, @@ -73,6 +102,7 @@ class CreateAngleTracker; class CreatePixelProbeTracker; class RemoveTracker; + class CreateTextAnnotationTracker; typedef std::set GeometricPrimitives; typedef std::set Annotations; @@ -155,5 +185,9 @@ { return probedLayer_; } + + void AddTextAnnotation(const std::string& label, + const ScenePoint2D& pointedPosition, + const ScenePoint2D& labelPosition); }; }