changeset 365:ef31240a73f6 am-2

no automatic call to moc and uic, CircleMeasureTracker using Orthanc fonts
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 31 Oct 2018 18:10:29 +0100
parents aad2f9293089
children a7de01c8fd29
files Applications/Samples/CMakeLists.txt Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp Applications/Samples/SimpleViewer/SimpleViewerApplication.h Applications/Samples/SimpleViewerApplicationSingleFile.h Applications/Samples/SingleFrameEditorApplication.h Framework/Layers/CircleMeasureTracker.cpp Framework/Layers/CircleMeasureTracker.h Framework/Viewport/CairoContext.cpp Framework/Viewport/CairoContext.h Framework/Viewport/CairoFont.h Framework/Widgets/CairoWidget.cpp Resources/CMake/OrthancStoneConfiguration.cmake Resources/CMake/QtConfiguration.cmake
diffstat 13 files changed, 196 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/CMakeLists.txt	Wed Oct 31 11:06:25 2018 +0100
+++ b/Applications/Samples/CMakeLists.txt	Wed Oct 31 18:10:29 2018 +0100
@@ -95,10 +95,20 @@
   list(APPEND SAMPLE_APPLICATIONS_SOURCES
     ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h
     ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp
+    )
+
+  ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES
     ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui
-    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp
     ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.ui
     )
+
+  ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.h
+    )
 endif()
 
 if (ENABLE_NATIVE)
@@ -144,7 +154,18 @@
         ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
         ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/mainQt.cpp
         )
-    elseif (ENABLE_WASM)
+
+      ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        )
+
+      ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
+        ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.h
+        )
+
+elseif (ENABLE_WASM)
         list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
             ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/mainWasm.cpp
             ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp
--- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp	Wed Oct 31 11:06:25 2018 +0100
+++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp	Wed Oct 31 18:10:29 2018 +0100
@@ -42,7 +42,8 @@
       }
       else if (application_.GetCurrentTool() == SimpleViewerApplication::Tools_CircleMeasure)
       {
-        return new CircleMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(), x, y, 255, 0, 0, 10);
+        return new CircleMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(),
+                                        x, y, 255, 0, 0, application_.GetFont());
       }
       else if (application_.GetCurrentTool() == SimpleViewerApplication::Tools_Crop)
       {
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Wed Oct 31 11:06:25 2018 +0100
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h	Wed Oct 31 18:10:29 2018 +0100
@@ -40,6 +40,7 @@
 #include "Qt/SimpleViewerMainWindow.h"
 #endif
 
+#include <Core/Images/Font.h>
 #include <Core/Logging.h>
 
 #include "ThumbnailInteractor.h"
@@ -94,7 +95,7 @@
     LayoutWidget*                   thumbnailsLayout_;
     LayerWidget*                    mainWidget_;
     std::vector<LayerWidget*>       thumbnails_;
-    std::map<std::string, std::vector<std::string>> instancesIdsPerSeriesId_;
+    std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
     std::map<std::string, Json::Value> seriesTags_;
     BaseCommandBuilder              commandBuilder_;
 
@@ -106,6 +107,8 @@
     std::unique_ptr<SmartLoader>    smartLoader_;
     std::unique_ptr<OrthancApiClient>      orthancApiClient_;
 
+    Orthanc::Font                   font_;
+
   public:
     SimpleViewerApplication(MessageBroker& broker) :
       IObserver(broker),
@@ -116,6 +119,7 @@
       wasmViewport1_(NULL),
       wasmViewport2_(NULL)
     {
+      font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
     }
 
     virtual void Finalize() {}
@@ -141,7 +145,16 @@
     void SelectSeriesInMainViewport(const std::string& seriesId);
 
     void SelectTool(Tools tool);
-    Tools GetCurrentTool() const {return currentTool_;}
+    
+    Tools GetCurrentTool() const
+    {
+      return currentTool_;
+    }
+
+    const Orthanc::Font& GetFont() const
+    {
+      return font_;
+    }
 
     void ExecuteAction(Actions action);
 
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Wed Oct 31 11:06:25 2018 +0100
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Wed Oct 31 18:10:29 2018 +0100
@@ -36,6 +36,7 @@
 #include "../../Platforms/Wasm/Defaults.h"
 #endif
 
+#include <Core/Images/Font.h>
 #include <Core/Logging.h>
 
 namespace OrthancStone
@@ -127,7 +128,8 @@
             }
             else if (application_.currentTool_ == Tools_CircleMeasure)
             {
-              return new CircleMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(), x, y, 255, 0, 0, 10);
+              return new CircleMeasureTracker(statusBar, dynamic_cast<LayerWidget&>(widget).GetSlice(),
+                                              x, y, 255, 0, 0, application_.GetFont());
             }
           }
           return NULL;
@@ -234,6 +236,8 @@
       std::auto_ptr<SmartLoader>           smartLoader_;
       std::auto_ptr<OrthancApiClient>      orthancApiClient_;
 
+      Orthanc::Font                        font_;
+
     public:
       SimpleViewerApplication(MessageBroker& broker) :
         IObserver(broker),
@@ -243,6 +247,7 @@
         wasmViewport1_(NULL),
         wasmViewport2_(NULL)
       {
+        font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
 //        DeclareIgnoredMessage(MessageType_Widget_ContentChanged);
       }
 
@@ -390,6 +395,11 @@
         smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
       }
 
+      const Orthanc::Font& GetFont() const
+      {
+        return font_;
+      }
+      
       virtual void OnPushButton1Clicked() {}
       virtual void OnPushButton2Clicked() {}
       virtual void OnTool1Clicked() { currentTool_ = Tools_LineMeasure;}
--- a/Applications/Samples/SingleFrameEditorApplication.h	Wed Oct 31 11:06:25 2018 +0100
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Wed Oct 31 18:10:29 2018 +0100
@@ -2788,7 +2788,7 @@
 
       // WARNING: The order of PixelSpacing is Y/X
       char buf[32];
-      sprintf(buf, "%0.08f\\%0.08f", pixelSpacingY, pixelSpacingX);
+      sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX);
       
       json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf;
 
--- a/Framework/Layers/CircleMeasureTracker.cpp	Wed Oct 31 11:06:25 2018 +0100
+++ b/Framework/Layers/CircleMeasureTracker.cpp	Wed Oct 31 18:10:29 2018 +0100
@@ -24,8 +24,6 @@
 
 #include "CircleMeasureTracker.h"
 
-#include "../Viewport/CairoFont.h"
-
 #include <stdio.h>
 
 namespace OrthancStone
@@ -37,14 +35,14 @@
                                              uint8_t red,
                                              uint8_t green,
                                              uint8_t blue,
-                                             unsigned int fontSize) :
+                                             const Orthanc::Font& font) :
     statusBar_(statusBar),
     slice_(slice),
     x1_(x),
     y1_(y),
     x2_(x),
     y2_(y),
-    fontSize_(fontSize)
+    font_(font)
   {
     color_[0] = red;
     color_[1] = green;
@@ -73,14 +71,8 @@
     cairo_stroke(cr);
     cairo_restore(cr);
 
-    if (fontSize_ != 0)
-    {
-      cairo_move_to(cr, x, y);
-#if ORTHANC_ENABLE_NATIVE==1 // text rendering currently fails in wasm
-      CairoFont font("sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
-      font.Draw(context, FormatRadius(), static_cast<double>(fontSize_) / zoom);
-#endif
-    }
+    //context.SetSourceColor(0, 255, 0);
+    context.DrawText(font_, FormatRadius(), x, y);
   }
     
 
--- a/Framework/Layers/CircleMeasureTracker.h	Wed Oct 31 11:06:25 2018 +0100
+++ b/Framework/Layers/CircleMeasureTracker.h	Wed Oct 31 18:10:29 2018 +0100
@@ -26,19 +26,21 @@
 #include "../Viewport/IStatusBar.h"
 #include "../Toolbox/CoordinateSystem3D.h"
 
+#include <Core/Images/Font.h>
+
 namespace OrthancStone
 {
   class CircleMeasureTracker : public IWorldSceneMouseTracker
   {
   private:
-    IStatusBar*         statusBar_;
-    CoordinateSystem3D  slice_;
-    double              x1_;
-    double              y1_;
-    double              x2_;
-    double              y2_;
-    uint8_t             color_[3];
-    unsigned int        fontSize_;
+    IStatusBar*           statusBar_;
+    CoordinateSystem3D    slice_;
+    double                x1_;
+    double                y1_;
+    double                x2_;
+    double                y2_;
+    uint8_t               color_[3];
+    const Orthanc::Font&  font_;
 
   public:
     CircleMeasureTracker(IStatusBar* statusBar,
@@ -48,7 +50,7 @@
                          uint8_t red,
                          uint8_t green,
                          uint8_t blue,
-                         unsigned int fontSize);
+                         const Orthanc::Font& font);
     
     virtual bool HasRender() const
     {
--- a/Framework/Viewport/CairoContext.cpp	Wed Oct 31 11:06:25 2018 +0100
+++ b/Framework/Viewport/CairoContext.cpp	Wed Oct 31 18:10:29 2018 +0100
@@ -59,4 +59,81 @@
                          static_cast<float>(green) / 255.0f,
                          static_cast<float>(blue) / 255.0f);
   }
+
+
+  class CairoContext::AlphaSurface : public boost::noncopyable
+  {
+  private:
+    cairo_surface_t  *surface_;
+
+  public:
+    AlphaSurface(unsigned int width,
+                 unsigned int height)
+    {
+      surface_ = cairo_image_surface_create(CAIRO_FORMAT_A8, width, height);
+      
+      if (!surface_)
+      {
+        // Should never occur
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+
+      if (cairo_surface_status(surface_) != CAIRO_STATUS_SUCCESS)
+      {
+        LOG(ERROR) << "Cannot create a Cairo surface";
+        cairo_surface_destroy(surface_);
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+    }
+    
+    ~AlphaSurface()
+    {
+      cairo_surface_destroy(surface_);
+    }
+
+    void GetAccessor(Orthanc::ImageAccessor& target)
+    {
+      target.AssignWritable(Orthanc::PixelFormat_Grayscale8,
+                            cairo_image_surface_get_width(surface_),
+                            cairo_image_surface_get_height(surface_),
+                            cairo_image_surface_get_stride(surface_),
+                            cairo_image_surface_get_data(surface_));
+    }
+
+    void Fill(cairo_t* cr,
+              double x,
+              double y)
+    {
+      cairo_surface_mark_dirty(surface_);
+      cairo_mask_surface(cr, surface_, x, y);
+      cairo_fill(cr);
+    }
+  };
+
+
+  void CairoContext::DrawText(const Orthanc::Font& font,
+                              const std::string& text,
+                              double x,
+                              double y)
+  {
+    unsigned int width, height;
+    font.ComputeTextExtent(width, height, text);
+    
+    AlphaSurface surface(width, height);
+
+    Orthanc::ImageAccessor accessor;
+    surface.GetAccessor(accessor);
+    font.Draw(accessor, text, 0, 0, 255);
+
+    double pixelX = x;
+    double pixelY = y;
+    cairo_user_to_device(context_, &pixelX, &pixelY);
+
+    cairo_save(context_);
+    cairo_identity_matrix(context_);
+
+    surface.Fill(context_, pixelX, pixelY);
+
+    cairo_restore(context_);
+  }
 }
--- a/Framework/Viewport/CairoContext.h	Wed Oct 31 11:06:25 2018 +0100
+++ b/Framework/Viewport/CairoContext.h	Wed Oct 31 18:10:29 2018 +0100
@@ -23,12 +23,16 @@
 
 #include "CairoSurface.h"
 
+#include <Core/Images/Font.h>
+
 namespace OrthancStone
 {
   // This is a RAII wrapper around the Cairo drawing context
   class CairoContext : public boost::noncopyable
   {
   private:
+    class AlphaSurface;
+    
     cairo_t*      context_;
     unsigned int  width_;
     unsigned int  height_;
@@ -61,5 +65,10 @@
     {
       SetSourceColor(color[0], color[1], color[2]);
     }
+
+    void DrawText(const Orthanc::Font& font,
+                  const std::string& text,
+                  double x,
+                  double y);      
   };
 }
--- a/Framework/Viewport/CairoFont.h	Wed Oct 31 11:06:25 2018 +0100
+++ b/Framework/Viewport/CairoFont.h	Wed Oct 31 18:10:29 2018 +0100
@@ -21,6 +21,14 @@
 
 #pragma once
 
+#if !defined(ORTHANC_SANDBOXED)
+#  error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+#  error The class CairoFont cannot be used in sandboxed environments
+#endif
+
 #include "CairoContext.h"
 
 namespace OrthancStone
--- a/Framework/Widgets/CairoWidget.cpp	Wed Oct 31 11:06:25 2018 +0100
+++ b/Framework/Widgets/CairoWidget.cpp	Wed Oct 31 18:10:29 2018 +0100
@@ -32,8 +32,8 @@
     return true;
   }
 
-  CairoWidget::CairoWidget(const std::string& name)
-    : WidgetBase(name)
+  CairoWidget::CairoWidget(const std::string& name) :
+    WidgetBase(name)
   {
   }
 
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Wed Oct 31 11:06:25 2018 +0100
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Wed Oct 31 18:10:29 2018 +0100
@@ -181,6 +181,7 @@
 
 if (NOT ORTHANC_SANDBOXED)
   set(PLATFORM_SOURCES
+    ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoFont.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceCommandBase.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceGetCommand.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServicePostCommand.cpp
@@ -271,7 +272,6 @@
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ViewportGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoContext.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoFont.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoSurface.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/IStatusBar.h
   ${ORTHANC_STONE_ROOT}/Framework/Viewport/IViewport.h
--- a/Resources/CMake/QtConfiguration.cmake	Wed Oct 31 11:06:25 2018 +0100
+++ b/Resources/CMake/QtConfiguration.cmake	Wed Oct 31 18:10:29 2018 +0100
@@ -17,10 +17,8 @@
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 
-# Instruct CMake to run moc automatically when needed.
-set(CMAKE_AUTOMOC ON)
-SET(CMAKE_AUTOUIC ON)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC OFF)
+set(CMAKE_AUTOUIC OFF)
 
 # Find the QtWidgets library
 find_package(Qt5Widgets QUIET)
@@ -32,12 +30,32 @@
     Qt5::Widgets
     Qt5::Core
     )
+
+  # Create aliases for the CMake commands
+  macro(ORTHANC_QT_WRAP_UI)
+    QT5_WRAP_UI(${ARGN})
+  endmacro()
+  
+  macro(ORTHANC_QT_WRAP_CPP)
+    QT5_WRAP_CPP(${ARGN})
+  endmacro()
+    
 else()
   message("Qt5 has not been found, trying with Qt4")
   find_package(Qt4 REQUIRED QtGui)
   link_libraries(
     Qt4::QtGui
     )
+
+  # Create aliases for the CMake commands
+  macro(ORTHANC_QT_WRAP_UI)
+    QT4_WRAP_UI(${ARGN})
+  endmacro()
+  
+  macro(ORTHANC_QT_WRAP_CPP)
+    QT4_WRAP_CPP(${ARGN})
+  endmacro()
+  
 endif()
 
 list(APPEND QT_SOURCES
@@ -46,5 +64,14 @@
   ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.cpp
   )
 
-include_directories(${ORTHANC_STONE_ROOT}/Applications/Qt/)
+
+# NB: Including CMAKE_CURRENT_BINARY_DIR is mandatory, as the CMake
+# macros for Qt will put their result in that directory, which cannot
+# be changed.
+# https://stackoverflow.com/a/4016784/881731
 
+include_directories(
+  ${ORTHANC_STONE_ROOT}/Applications/Qt/
+  ${CMAKE_CURRENT_BINARY_DIR}
+  )
+