changeset 287:2038d76bf13f am-2

interaction with HTML/JS
author am@osimis.io
date Thu, 30 Aug 2018 11:36:36 +0200
parents 6b3d91857b96
children 8c8da145fefa
files Applications/IBasicApplication.h Applications/Samples/SimpleViewerApplication.h Applications/Samples/Web/simple-viewer.html Applications/Samples/Web/simple-viewer.ts Applications/Samples/Web/tsconfig-samples.json Framework/Layers/CircleMeasureTracker.cpp Framework/Layers/LineMeasureTracker.cpp Platforms/Wasm/Defaults.cpp Platforms/Wasm/Defaults.h Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h Platforms/Wasm/default-library.js Platforms/Wasm/tsconfig-stone.json Platforms/Wasm/wasm-application-runner.ts Platforms/Wasm/wasm-application.ts Resources/CMake/OrthancStoneConfiguration.cmake TODO
diffstat 16 files changed, 243 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/IBasicApplication.h	Tue Aug 28 15:34:20 2018 +0200
+++ b/Applications/IBasicApplication.h	Thu Aug 30 11:36:36 2018 +0200
@@ -24,6 +24,7 @@
 #include "BasicApplicationContext.h"
 #include <boost/program_options.hpp>
 #include "../Framework/Viewport/WidgetViewport.h"
+#include "json/json.h"
 
 namespace OrthancStone
 {
@@ -49,7 +50,6 @@
     virtual IWidget* GetCentralWidget() = 0;
 
     virtual void Finalize() = 0;
-
   };
 
 }
--- a/Applications/Samples/SimpleViewerApplication.h	Tue Aug 28 15:34:20 2018 +0200
+++ b/Applications/Samples/SimpleViewerApplication.h	Thu Aug 30 11:36:36 2018 +0200
@@ -31,6 +31,10 @@
 #include "../../Framework/Messages/IObserver.h"
 #include "../../Framework/SmartLoader.h"
 
+#if ORTHANC_ENABLE_WASM==1
+#include "../../Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h"
+#include "../../Platforms/Wasm/Defaults.h"
+#endif
 #include <Core/Logging.h>
 
 namespace OrthancStone
@@ -39,6 +43,9 @@
   {
     class SimpleViewerApplication :
         public SampleApplicationBase,
+#if ORTHANC_ENABLE_WASM==1
+        public IStoneApplicationToWebApplicationAdapter,
+#endif
         public IObserver
     {
     private:
@@ -178,6 +185,7 @@
       LayerWidget*                    mainWidget_;
       std::vector<LayerWidget*>       thumbnails_;
       std::map<std::string, std::vector<std::string>> instancesIdsPerSeriesId_;
+      std::map<std::string, Json::Value> seriesTags_;
 
       unsigned int                    currentInstanceIndex_;
       OrthancStone::WidgetViewport*   wasmViewport1_;
@@ -297,6 +305,7 @@
         {
           // keep track of all instances IDs
           const std::string& seriesId = response["ID"].asString();
+          seriesTags_[seriesId] = response;
           instancesIdsPerSeriesId_[seriesId] = std::vector<std::string>();
           for (size_t i = 0; i < response["Instances"].size(); i++)
           {
@@ -351,19 +360,12 @@
         }
       }
 
-#if ORTHANC_ENABLE_WASM==1
-      virtual void InitializeWasm() {
-
-        AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
-        AttachWidgetToWasmViewport("canvas2", mainWidget_);
-      }
-#endif
-
-
-
       void SelectSeriesInMainViewport(const std::string& seriesId)
       {
         mainWidget_->ReplaceLayer(0, smartLoader_->GetFrame(instancesIdsPerSeriesId_[seriesId][0], 0));
+#if ORTHANC_ENABLE_WASM==1
+        NotifyStatusUpdateFromCppToWeb("series-description=" + seriesTags_[seriesId]["MainDicomTags"]["SeriesDescription"].asString());
+#endif
       }
 
       virtual void OnPushButton1Clicked() {}
@@ -381,6 +383,33 @@
         pushButton1 = "action1";
         pushButton2 = "action2";
       }
+
+#if ORTHANC_ENABLE_WASM==1
+      virtual void HandleMessageFromWeb(std::string& output, const std::string& input) {
+        if (input == "select-tool:line-measure")
+        {
+          currentTool_ = Tools_LineMeasure;
+          NotifyStatusUpdateFromCppToWeb("currentTool=line-measure");
+        }
+        else if (input == "select-tool:circle-measure")
+        {
+          currentTool_ = Tools_CircleMeasure;
+          NotifyStatusUpdateFromCppToWeb("currentTool=circle-measure");
+        }
+
+        output = "ok";
+      }
+
+      virtual void NotifyStatusUpdateFromCppToWeb(const std::string& statusUpdateMessage) {
+        UpdateStoneApplicationStatusFromCpp(statusUpdateMessage.c_str());
+      }
+
+      virtual void InitializeWasm() {
+
+        AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
+        AttachWidgetToWasmViewport("canvas2", mainWidget_);
+      }
+#endif
     };
 
 
--- a/Applications/Samples/Web/simple-viewer.html	Tue Aug 28 15:34:20 2018 +0200
+++ b/Applications/Samples/Web/simple-viewer.html	Thu Aug 30 11:36:36 2018 +0200
@@ -13,15 +13,20 @@
     <link href="samples-styles.css" rel="stylesheet" />
 
 <body>
+  <div id="breadcrumb">
+    <span id="patient-id"></span>
+    <span id="study-description"></span>
+    <span id="series-description"></span>
+  </div>
   <div>
     <canvas id="canvas" data-width-ratio="20" data-height-ratio="50"></canvas>
     <canvas id="canvas2" data-width-ratio="70" data-height-ratio="50"></canvas>
   </div>
-  <div>
-    <button id="tool1">tool1</button>
-    <button id="tool2">tool2</button>
-    <button id="pushBouton1">action1</button>
-    <button id="pushBouton2">action2</button>
+  <div id="toolbox">
+    <input tool-selector="line-measure" type="radio" name="radio-tool-selector" class="tool-selector">line
+    <input tool-selector="circle-measure" type="radio" name="radio-tool-selector" class="tool-selector">circle
+    <button action-trigger="action1" class="action-trigger">action1</button>
+    <button action-trigger="action2" class="action-trigger">action2</button>
   </div>
   <script type="text/javascript" src="app-simple-viewer.js"></script>
 </body>
--- a/Applications/Samples/Web/simple-viewer.ts	Tue Aug 28 15:34:20 2018 +0200
+++ b/Applications/Samples/Web/simple-viewer.ts	Thu Aug 30 11:36:36 2018 +0200
@@ -1,3 +1,39 @@
-///<reference path='../../../Platforms/Wasm/wasm-application.ts'/>
+///<reference path='../../../Platforms/Wasm/wasm-application-runner.ts'/>
 
 InitializeWasmApplication("OrthancStoneSimpleViewer", "/orthanc");
+
+function SelectTool(toolName: string) {
+    SendMessageToStoneApplication("select-tool:" + toolName);
+}
+
+function PerformAction(actionName: string) {
+    SendMessageToStoneApplication("perform-action:" + actionName);
+}
+
+//initializes the buttons
+//-----------------------
+// install "SelectTool" handlers
+document.querySelectorAll("[tool-selector]").forEach((e) => {
+    console.log(e);
+    (e as HTMLInputElement).addEventListener("click", () => {
+        console.log(e);
+        SelectTool(e.attributes["tool-selector"].value);
+    });
+});
+
+// install "PerformAction" handlers
+document.querySelectorAll("[action-trigger]").forEach((e) => {
+    (e as HTMLInputElement).addEventListener("click", () => {
+        PerformAction(e.attributes["action-trigger"].value);
+    });
+});
+
+// this method is called "from the C++ code" when the StoneApplication is updated.
+// it can be used to update the UI of the application
+function UpdateWebApplication(statusUpdateMessage: string) {
+  console.log(statusUpdateMessage);
+  
+  if (statusUpdateMessage.startsWith("series-description=")) {
+      document.getElementById("series-description").innerText = statusUpdateMessage.split("=")[1];
+  }
+}
--- a/Applications/Samples/Web/tsconfig-samples.json	Tue Aug 28 15:34:20 2018 +0200
+++ b/Applications/Samples/Web/tsconfig-samples.json	Thu Aug 30 11:36:36 2018 +0200
@@ -4,7 +4,8 @@
         "sourceMap": false,
         "lib" : [
             "es2017",
-            "dom"
+            "dom",
+            "dom.iterable"
         ]
     }
 }
--- a/Framework/Layers/CircleMeasureTracker.cpp	Tue Aug 28 15:34:20 2018 +0200
+++ b/Framework/Layers/CircleMeasureTracker.cpp	Thu Aug 30 11:36:36 2018 +0200
@@ -76,8 +76,10 @@
     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
     }
   }
     
--- a/Framework/Layers/LineMeasureTracker.cpp	Tue Aug 28 15:34:20 2018 +0200
+++ b/Framework/Layers/LineMeasureTracker.cpp	Thu Aug 30 11:36:36 2018 +0200
@@ -63,8 +63,10 @@
     if (fontSize_ != 0)
     {
       cairo_move_to(cr, x2_, y2_ - static_cast<double>(fontSize_) / zoom);
+#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, FormatLength(), static_cast<double>(fontSize_) / zoom);
+#endif
     }
   }
     
--- a/Platforms/Wasm/Defaults.cpp	Tue Aug 28 15:34:20 2018 +0200
+++ b/Platforms/Wasm/Defaults.cpp	Thu Aug 30 11:36:36 2018 +0200
@@ -7,6 +7,7 @@
 #include <Framework/Widgets/LayerWidget.h>
 #include <algorithm>
 #include "Applications/Wasm/StartupParametersBuilder.h"
+#include "Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h"
 
 static unsigned int width_ = 0;
 static unsigned int height_ = 0;
@@ -14,6 +15,7 @@
 /**********************************/
 
 static std::unique_ptr<OrthancStone::IBasicApplication> application;
+static OrthancStone::IStoneApplicationToWebApplicationAdapter* applicationWebAdapter = NULL;
 static std::unique_ptr<OrthancStone::BasicApplicationContext> context;
 static OrthancStone::StartupParametersBuilder startupParametersBuilder;
 static OrthancStone::MessageBroker broker;
@@ -43,7 +45,7 @@
   ViewportHandle EMSCRIPTEN_KEEPALIVE CreateCppViewport() {
     
     std::shared_ptr<OrthancStone::WidgetViewport> viewport(new OrthancStone::WidgetViewport);
-    printf("viewport %x\n", viewport.get());
+    printf("viewport %x\n", (int)viewport.get());
 
     viewports_.push_back(viewport);
 
@@ -67,6 +69,7 @@
     printf("CreateWasmApplication\n");
 
     application.reset(CreateUserApplication(broker));
+    applicationWebAdapter = dynamic_cast<OrthancStone::IStoneApplicationToWebApplicationAdapter*>(application.get()); 
     WasmWebService::SetBroker(broker);
 
     startupParametersBuilder.Clear();
@@ -254,6 +257,18 @@
     viewport->MouseLeave();
   }
 
+  const char* EMSCRIPTEN_KEEPALIVE SendMessageToStoneApplication(const char* message) 
+  {
+    static std::string output; // we don't want the string to be deallocated when we return to JS code so we always use the same string (this is fine since JS is single-thread)
+
+    if (applicationWebAdapter != NULL) {
+      printf("sending message to C++");
+      applicationWebAdapter->HandleMessageFromWeb(output, std::string(message));
+      return output.c_str();
+    }
+    return "This stone application does not have a Web Adapter";
+  }
+
 
 #ifdef __cplusplus
 }
--- a/Platforms/Wasm/Defaults.h	Tue Aug 28 15:34:20 2018 +0200
+++ b/Platforms/Wasm/Defaults.h	Thu Aug 30 11:36:36 2018 +0200
@@ -16,6 +16,7 @@
   
   // JS methods accessible from C++
   extern void ScheduleWebViewportRedrawFromCpp(ViewportHandle cppViewportHandle);
+  extern void UpdateStoneApplicationStatusFromCpp(const char* statusUpdateMessage);
   
   // C++ methods accessible from JS
   extern void EMSCRIPTEN_KEEPALIVE CreateWasmApplication(ViewportHandle cppViewportHandle);
@@ -30,7 +31,7 @@
 
 namespace OrthancStone {
 
-  // default Ovserver to trigger Viewport redraw when something changes in the Viewport
+  // default Observer to trigger Viewport redraw when something changes in the Viewport
   class ViewportContentChangedObserver :
     public OrthancStone::IViewport::IObserver
   {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h	Thu Aug 30 11:36:36 2018 +0200
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <string>
+
+namespace OrthancStone
+{
+  class IStoneApplicationToWebApplicationAdapter
+  {
+    public:
+      virtual void HandleMessageFromWeb(std::string& output, const std::string& input) = 0;
+      virtual void NotifyStatusUpdateFromCppToWeb(const std::string& statusUpdateMessage) = 0;
+  };
+}
\ No newline at end of file
--- a/Platforms/Wasm/default-library.js	Tue Aug 28 15:34:20 2018 +0200
+++ b/Platforms/Wasm/default-library.js	Thu Aug 30 11:36:36 2018 +0200
@@ -6,6 +6,11 @@
   },
   CreateWasmViewportFromCpp: function(htmlCanvasId) {
     return CreateWasmViewport(htmlCanvasId);
+  },
+  // each time the StoneApplication updates its status, it may signal it through this method. i.e, to change the status of a button in the web interface
+  UpdateStoneApplicationStatusFromCpp: function(statusUpdateMessage) {
+    var statusUpdateMessage_ = UTF8ToString(statusUpdateMessage);
+    UpdateWebApplication(statusUpdateMessage_);
   }
 });
   
\ No newline at end of file
--- a/Platforms/Wasm/tsconfig-stone.json	Tue Aug 28 15:34:20 2018 +0200
+++ b/Platforms/Wasm/tsconfig-stone.json	Thu Aug 30 11:36:36 2018 +0200
@@ -1,7 +1,7 @@
 {
     "include" : [
         "../../../Platforms/Wasm/stone-framework-loader.ts",
-        "../../../Platforms/Wasm/wasm-application.ts",
+        "../../../Platforms/Wasm/wasm-application-runner.ts",
         "../../../Platforms/Wasm/wasm-viewport.ts"
     ]
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Platforms/Wasm/wasm-application-runner.ts	Thu Aug 30 11:36:36 2018 +0200
@@ -0,0 +1,112 @@
+///<reference path='stone-framework-loader.ts'/>
+///<reference path='wasm-viewport.ts'/>
+
+if (!('WebAssembly' in window)) {
+  alert('Sorry, your browser does not support WebAssembly :(');
+}
+
+declare var StoneFrameworkModule : Stone.Framework;
+
+// global functions
+var WasmWebService_NotifyError: Function = null;
+var WasmWebService_NotifySuccess: Function = null;
+var WasmWebService_SetBaseUri: Function = null;
+var NotifyUpdateContent: Function = null;
+var SetStartupParameter: Function = null;
+var CreateWasmApplication: Function = null;
+var CreateCppViewport: Function = null;
+var ReleaseCppViewport: Function = null;
+var StartWasmApplication: Function = null;
+var SendMessageToStoneApplication: Function = null;
+
+
+function UpdateContentThread() {
+  if (NotifyUpdateContent != null) {
+    NotifyUpdateContent();
+  }
+
+  setTimeout(UpdateContentThread, 100);  // Update the viewport content every 100ms if need be
+}
+
+
+function GetUriParameters() {
+  var parameters = window.location.search.substr(1);
+
+  if (parameters != null &&
+    parameters != '') {
+    var result = {};
+    var tokens = parameters.split('&');
+
+    for (var i = 0; i < tokens.length; i++) {
+      var tmp = tokens[i].split('=');
+      if (tmp.length == 2) {
+        result[tmp[0]] = decodeURIComponent(tmp[1]);
+      }
+    }
+
+    return result;
+  }
+  else {
+    return {};
+  }
+}
+
+// function UpdateWebApplication(statusUpdateMessage: string) {
+//   console.log(statusUpdateMessage);
+// }
+
+function _InitializeWasmApplication(canvasId: string, orthancBaseUrl: string): void {
+
+  /************************************** */
+  CreateWasmApplication();
+  WasmWebService_SetBaseUri(orthancBaseUrl);
+
+
+  // parse uri and transmit the parameters to the app before initializing it
+  var parameters = GetUriParameters();
+
+  for (var key in parameters) {
+    if (parameters.hasOwnProperty(key)) {
+      SetStartupParameter(key, parameters[key]);
+    }
+  }
+
+  StartWasmApplication();
+  /************************************** */
+
+  UpdateContentThread();
+}
+
+function InitializeWasmApplication(wasmModuleName: string, orthancBaseUrl: string) {
+  
+  Stone.Framework.Configure(wasmModuleName);
+
+  // Wait for the Orthanc Framework to be initialized (this initializes
+  // the WebAssembly environment) and then, create and initialize the Wasm application
+  Stone.Framework.Initialize(true, function () {
+
+    console.log("Connecting C++ methods to JS methods");
+    
+    SetStartupParameter = StoneFrameworkModule.cwrap('SetStartupParameter', null, ['string', 'string']);
+    CreateWasmApplication = StoneFrameworkModule.cwrap('CreateWasmApplication', null, ['number']);
+    CreateCppViewport = StoneFrameworkModule.cwrap('CreateCppViewport', 'number', []);
+    ReleaseCppViewport = StoneFrameworkModule.cwrap('ReleaseCppViewport', null, ['number']);
+    StartWasmApplication = StoneFrameworkModule.cwrap('StartWasmApplication', null, ['number']);
+
+    WasmWebService_NotifySuccess = StoneFrameworkModule.cwrap('WasmWebService_NotifySuccess', null, ['number', 'string', 'array', 'number', 'number']);
+    WasmWebService_NotifyError = StoneFrameworkModule.cwrap('WasmWebService_NotifyError', null, ['number', 'string', 'number']);
+    WasmWebService_SetBaseUri = StoneFrameworkModule.cwrap('WasmWebService_SetBaseUri', null, ['string']);
+    NotifyUpdateContent = StoneFrameworkModule.cwrap('NotifyUpdateContent', null, []);
+
+    SendMessageToStoneApplication = StoneFrameworkModule.cwrap('SendMessageToStoneApplication', 'string', ['string']);
+
+    console.log("Connecting C++ methods to JS methods - done");
+
+    // Prevent scrolling
+    document.body.addEventListener('touchmove', function (event) {
+      event.preventDefault();
+    }, false);
+
+    _InitializeWasmApplication("canvas", orthancBaseUrl);
+  });
+}
\ No newline at end of file
--- a/Platforms/Wasm/wasm-application.ts	Tue Aug 28 15:34:20 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-///<reference path='stone-framework-loader.ts'/>
-///<reference path='wasm-viewport.ts'/>
-
-if (!('WebAssembly' in window)) {
-  alert('Sorry, your browser does not support WebAssembly :(');
-}
-
-declare var StoneFrameworkModule : Stone.Framework;
-
-// global functions
-var WasmWebService_NotifyError: Function = null;
-var WasmWebService_NotifySuccess: Function = null;
-var WasmWebService_SetBaseUri: Function = null;
-var NotifyUpdateContent: Function = null;
-var SetStartupParameter: Function = null;
-var CreateWasmApplication: Function = null;
-var CreateCppViewport: Function = null;
-var ReleaseCppViewport: Function = null;
-var StartWasmApplication: Function = null;
-
-
-function UpdateContentThread() {
-  if (NotifyUpdateContent != null) {
-    NotifyUpdateContent();
-  }
-
-  setTimeout(UpdateContentThread, 100);  // Update the viewport content every 100ms if need be
-}
-
-
-function GetUriParameters() {
-  var parameters = window.location.search.substr(1);
-
-  if (parameters != null &&
-    parameters != '') {
-    var result = {};
-    var tokens = parameters.split('&');
-
-    for (var i = 0; i < tokens.length; i++) {
-      var tmp = tokens[i].split('=');
-      if (tmp.length == 2) {
-        result[tmp[0]] = decodeURIComponent(tmp[1]);
-      }
-    }
-
-    return result;
-  }
-  else {
-    return {};
-  }
-}
-
-module Stone {
-
-  export class WasmApplication {
-
-    private viewport_: WasmViewport;
-    private canvasId_: string;
-
-    private pimpl_: any; // Private pointer to the underlying WebAssembly C++ object
-
-    public constructor(canvasId: string) {
-      this.canvasId_ = canvasId;
-      //this.module_ = module;
-    }
-  }
-}
-
-
-function _InitializeWasmApplication(canvasId: string, orthancBaseUrl: string): void {
-
-  /************************************** */
-  CreateWasmApplication();
-  WasmWebService_SetBaseUri(orthancBaseUrl);
-
-
-  // parse uri and transmit the parameters to the app before initializing it
-  var parameters = GetUriParameters();
-
-  for (var key in parameters) {
-    if (parameters.hasOwnProperty(key)) {
-      SetStartupParameter(key, parameters[key]);
-    }
-  }
-
-  StartWasmApplication();
-  /************************************** */
-
-  UpdateContentThread();
-}
-
-function InitializeWasmApplication(wasmModuleName: string, orthancBaseUrl: string) {
-  
-  Stone.Framework.Configure(wasmModuleName);
-
-  // Wait for the Orthanc Framework to be initialized (this initializes
-  // the WebAssembly environment) and then, create and initialize the Wasm application
-  Stone.Framework.Initialize(true, function () {
-
-    console.log("Connecting C++ methods to JS methods");
-    
-    SetStartupParameter = StoneFrameworkModule.cwrap('SetStartupParameter', null, ['string', 'string']);
-    CreateWasmApplication = StoneFrameworkModule.cwrap('CreateWasmApplication', null, ['number']);
-    CreateCppViewport = StoneFrameworkModule.cwrap('CreateCppViewport', 'number', []);
-    ReleaseCppViewport = StoneFrameworkModule.cwrap('ReleaseCppViewport', null, ['number']);
-    StartWasmApplication = StoneFrameworkModule.cwrap('StartWasmApplication', null, ['number']);
-
-    WasmWebService_NotifySuccess = StoneFrameworkModule.cwrap('WasmWebService_NotifySuccess', null, ['number', 'string', 'array', 'number', 'number']);
-    WasmWebService_NotifyError = StoneFrameworkModule.cwrap('WasmWebService_NotifyError', null, ['number', 'string', 'number']);
-    WasmWebService_SetBaseUri = StoneFrameworkModule.cwrap('WasmWebService_SetBaseUri', null, ['string']);
-    NotifyUpdateContent = StoneFrameworkModule.cwrap('NotifyUpdateContent', null, []);
-
-    console.log("Connecting C++ methods to JS methods - done - 2");
-
-    // Prevent scrolling
-    document.body.addEventListener('touchmove', function (event) {
-      event.preventDefault();
-    }, false);
-
-    _InitializeWasmApplication("canvas", orthancBaseUrl);
-  });
-}
\ No newline at end of file
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Aug 28 15:34:20 2018 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Thu Aug 30 11:36:36 2018 +0200
@@ -199,6 +199,7 @@
     ${ORTHANC_STONE_ROOT}/Platforms/Wasm/Defaults.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Wasm/WasmWebService.cpp
     ${ORTHANC_STONE_ROOT}/Platforms/Wasm/WasmViewport.cpp
+    ${ORTHANC_STONE_ROOT}/Platforms/Wasm/IStoneApplicationToWebApplicationAdapter.h
   )
 endif()
 
--- a/TODO	Tue Aug 28 15:34:20 2018 +0200
+++ b/TODO	Thu Aug 30 11:36:36 2018 +0200
@@ -9,14 +9,6 @@
 * Documentation
 * Interface with DICOMweb
 * LayoutPetCtFusionApplication: fix initial view
-* Allow Interactor to create Pan/ZoomMouseTracker in IWorldSceneMouseTracker* CreateMouseTracker 
-  (problem: PanMouseTracker is a IMouseTracker and CreateMouseTracker shall return a IWorldSceneMouseTracker).
-  WorldSceneWidet shall not create Pan/ZoomMouseTracker when the Interactor does not create one
-* Update SimpleViewer sample to have 2 buttons to select the measure tracker
-
-Bugs
-----
-* LineMeasureTracker rendering generates "memory access out of bounds" in WASM
 
 
 ---------------------------------
@@ -33,7 +25,6 @@
 Optimizations
 -------------
 
-* Add cache in "SmartLoader" by returning a "OrthancFrameLayerSource" for a frame that has already been loaded
 * Tune number of loading threads in LayeredSceneWidget
 * LayoutWidget: Do not update full background if only 1 widget has changed
 * LayoutWidget: Threads to refresh each child