# HG changeset patch # User Benjamin Golinvaux <bgo@osimis.io> # Date 1553009347 -3600 # Node ID 7428c5dfa5dfa54b7fe1196d994ccbba4c2fd6ee # Parent 9d124a81c34ab91bc64078bebbe74bd328194f72 Initial commit non working app diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/AppStatus.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/AppStatus.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,27 @@ +#pragma once + +#include <string> + + +namespace CtPetDoseStructFusion +{ + struct AppStatus + { + std::string patientId; + std::string studyDescription; + std::string currentSeriesIdInMainViewport; + // note: if you add members here, update the serialization code below and deserialization in ct-dose-struct-fusion.ts -> onAppStatusUpdated() + + + AppStatus() + { + } + + void ToJson(Json::Value &output) const + { + output["patientId"] = patientId; + output["studyDescription"] = studyDescription; + output["currentSeriesIdInMainViewport"] = currentSeriesIdInMainViewport; + } + }; +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/CMakeLists.txt Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,145 @@ +cmake_minimum_required(VERSION 2.8.3) +project(CtPetDoseStructFusion) + +include(../../../Resources/CMake/OrthancStoneParameters.cmake) + +if (OPENSSL_NO_CAPIENG) +add_definitions(-DOPENSSL_NO_CAPIENG=1) +endif() + +set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application") +set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application") +set(ENABLE_WASM OFF CACHE BOOL "Target WASM application") + +if (ENABLE_WASM) + ##################################################################### + ## Configuration of the Emscripten compiler for WebAssembly target + ##################################################################### + + set(WASM_FLAGS "-s WASM=1") + set(WASM_FLAGS "${WASM_FLAGS} -s STRICT=1") # drops support for all deprecated build options + set(WASM_FLAGS "${WASM_FLAGS} -s FILESYSTEM=1") # if we don't include it, gen_uuid.c fails to build because srand, getpid(), ... are not defined + set(WASM_FLAGS "${WASM_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0") # actually enable exception catching + set(WASM_FLAGS "${WASM_FLAGS} -s ERROR_ON_MISSING_LIBRARIES=1") + + if (CMAKE_BUILD_TYPE MATCHES DEBUG) + set(WASM_FLAGS "${WASM_FLAGS} -g4") # generate debug information + set(WASM_FLAGS "${WASM_FLAGS} -s ASSERTIONS=2") # more runtime checks + else() + set(WASM_FLAGS "${WASM_FLAGS} -Os") # optimize for web (speed and size) + endif() + + set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module") + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}") + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_FLAGS}") # not always clear which flags are for the compiler and which one are for the linker -> pass them all to the linker too + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"'") + +# +-------------------------------+ +# | Commented for now! | +# +-------------------------------+ + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1") + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912") + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=128000000") + + add_definitions(-DORTHANC_ENABLE_WASM=1) + set(ORTHANC_SANDBOXED ON) + +elseif (ENABLE_QT OR ENABLE_SDL) + + set(ENABLE_NATIVE ON) + set(ORTHANC_SANDBOXED OFF) + set(ENABLE_CRYPTO_OPTIONS ON) + set(ENABLE_GOOGLE_TEST ON) + set(ENABLE_WEB_CLIENT ON) + +endif() + +##################################################################### +## Configuration for Orthanc +##################################################################### + +if (ORTHANC_STONE_VERSION STREQUAL "mainline") + set(ORTHANC_FRAMEWORK_VERSION "mainline") + set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg") +else() + set(ORTHANC_FRAMEWORK_VERSION "1.4.1") + set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web") +endif() + +set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")") +set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"") +set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"") + +##################################################################### +## Build a static library containing the Orthanc Stone framework +##################################################################### + + +LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options) + +include(../../Resources/CMake/OrthancStoneConfiguration.cmake) + +add_library(OrthancStone STATIC + ${ORTHANC_STONE_SOURCES} + ) + +##################################################################### +## Build the CDSF applications +##################################################################### + +if (ENABLE_QT OR ENABLE_WASM) + if (ENABLE_QT) + list(APPEND CDSF_APPLICATION_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.ui + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Qt/mainQt.cpp + ) + + ORTHANC_QT_WRAP_UI(CDSF_APPLICATION_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.ui + ) + + ORTHANC_QT_WRAP_CPP(CDSF_APPLICATION_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.h + ) + + elseif (ENABLE_WASM) + list(APPEND CDSF_APPLICATION_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Wasm/mainWasm.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Wasm/CtPetDoseStructFusionWasmApplicationAdapter.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Wasm/CtPetDoseStructFusionWasmApplicationAdapter.h + ${STONE_WASM_SOURCES} + ) + endif() + + add_executable(CtPetDoseStructFusionApplication + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/AppStatus.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/MainWidgetInteractor.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/MainWidgetInteractor.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/Messages.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/CtPetDoseStructFusionApplication.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/CtPetDoseStructFusionApplication.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/ThumbnailInteractor.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/CtPetDoseStructFusion/ThumbnailInteractor.h + ${CDSF_APPLICATION_SOURCES} + ) + target_link_libraries(CtPetDoseStructFusionApplication OrthancStone) + +endif() + + + + + + + + + diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/CtPetDoseStructFusionApplication.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/CtPetDoseStructFusionApplication.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,239 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "CtPetDoseStructFusionApplication.h" + +#if ORTHANC_ENABLE_QT == 1 +# include "Qt/CtPetDoseStructFusionMainWindow.h" +#endif + +#if ORTHANC_ENABLE_WASM == 1 +# include <Platforms/Wasm/WasmViewport.h> +#endif + +namespace CtPetDoseStructFusion +{ + + void CtPetDoseStructFusionApplication::Initialize(StoneApplicationContext* context, + IStatusBar& statusBar, + const boost::program_options::variables_map& parameters) + { + using namespace OrthancStone; + + context_ = context; + statusBar_ = &statusBar; + + {// initialize viewports and layout + mainLayout_ = new LayoutWidget("main-layout"); + mainLayout_->SetPadding(10); + mainLayout_->SetBackgroundCleared(true); + mainLayout_->SetBackgroundColor(0, 0, 0); + mainLayout_->SetHorizontal(); + + thumbnailsLayout_ = new LayoutWidget("thumbnail-layout"); + thumbnailsLayout_->SetPadding(10); + thumbnailsLayout_->SetBackgroundCleared(true); + thumbnailsLayout_->SetBackgroundColor(50, 50, 50); + thumbnailsLayout_->SetVertical(); + + mainWidget_ = new SliceViewerWidget(IObserver::GetBroker(), "main-viewport"); + //mainWidget_->RegisterObserver(*this); + + // hierarchy + mainLayout_->AddWidget(thumbnailsLayout_); + mainLayout_->AddWidget(mainWidget_); + + // sources + smartLoader_.reset(new SmartLoader(IObserver::GetBroker(), context->GetOrthancApiClient())); + smartLoader_->SetImageQuality(SliceImageQuality_FullPam); + + mainLayout_->SetTransmitMouseOver(true); + mainWidgetInteractor_.reset(new MainWidgetInteractor(*this)); + mainWidget_->SetInteractor(*mainWidgetInteractor_); + thumbnailInteractor_.reset(new ThumbnailInteractor(*this)); + } + + statusBar.SetMessage("Use the key \"s\" to reinitialize the layout"); + statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport"); + +#if TODO_BGO_CDSF + if (parameters.count("studyId") < 1) + { + LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc"; + context->GetOrthancApiClient().GetJsonAsync("/studies", new Callable<CtPetDoseStructFusionApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &CtPetDoseStructFusionApplication::OnStudyListReceived)); + } + else + { + SelectStudy(parameters["studyId"].as<std::string>()); + } +#endif +// TODO_BGO_CDSF + } + + + void CtPetDoseStructFusionApplication::DeclareStartupOptions(boost::program_options::options_description& options) + { + boost::program_options::options_description generic("Sample options"); +#if TODO_BGO_CDSF + generic.add_options() + ("studyId", boost::program_options::value<std::string>(), + "Orthanc ID of the study") + ; + + options.add(generic); +#endif + } + + void CtPetDoseStructFusionApplication::OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& response = message.GetJson(); + + if (response.isArray() && + response.size() >= 1) + { + SelectStudy(response[0].asString()); + } + } + void CtPetDoseStructFusionApplication::OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& response = message.GetJson(); + + if (response.isObject() && response["Series"].isArray()) + { + for (size_t i=0; i < response["Series"].size(); i++) + { + context_->GetOrthancApiClient().GetJsonAsync( + "/series/" + response["Series"][(int)i].asString(), + new Callable< + CtPetDoseStructFusionApplication + , OrthancApiClient::JsonResponseReadyMessage>( + *this, + &CtPetDoseStructFusionApplication::OnSeriesReceived + ) + ); + } + } + } + + void CtPetDoseStructFusionApplication::OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& response = message.GetJson(); + + if (response.isObject() && + response["Instances"].isArray() && + response["Instances"].size() > 0) + { + // 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++) + { + const std::string& instanceId = response["Instances"][static_cast<int>(i)].asString(); + instancesIdsPerSeriesId_[seriesId].push_back(instanceId); + } + + // load the first instance in the thumbnail + LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]); + + // if this is the first thumbnail loaded, load the first instance in the mainWidget + if (mainWidget_->GetLayerCount() == 0) + { + smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0); + } + } + } + + void CtPetDoseStructFusionApplication::LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId) + { + LOG(INFO) << "Loading thumbnail for series " << seriesId; + + SliceViewerWidget* thumbnailWidget = + new SliceViewerWidget(IObserver::GetBroker(), "thumbnail-series-" + seriesId); + thumbnails_.push_back(thumbnailWidget); + thumbnailsLayout_->AddWidget(thumbnailWidget); + + thumbnailWidget->RegisterObserverCallback( + new Callable<CtPetDoseStructFusionApplication, SliceViewerWidget::GeometryChangedMessage> + (*this, &CtPetDoseStructFusionApplication::OnWidgetGeometryChanged)); + + smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0); + thumbnailWidget->SetInteractor(*thumbnailInteractor_); + } + + void CtPetDoseStructFusionApplication::SelectStudy(const std::string& studyId) + { + context_->GetOrthancApiClient().GetJsonAsync("/studies/" + studyId, new Callable<CtPetDoseStructFusionApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &CtPetDoseStructFusionApplication::OnStudyReceived)); + } + + void CtPetDoseStructFusionApplication::OnWidgetGeometryChanged(const SliceViewerWidget::GeometryChangedMessage& message) + { + // TODO: The "const_cast" could probably be replaced by "mainWidget_" + const_cast<SliceViewerWidget&>(message.GetOrigin()).FitContent(); + } + + void CtPetDoseStructFusionApplication::SelectSeriesInMainViewport(const std::string& seriesId) + { + smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0); + } + + bool CtPetDoseStructFusionApplication::Handle(const StoneSampleCommands::SelectTool& value) ORTHANC_OVERRIDE + { + currentTool_ = value.tool; + return true; + } + + bool CtPetDoseStructFusionApplication::Handle(const StoneSampleCommands::Action& value) ORTHANC_OVERRIDE + { + switch (value.type) + { + case ActionType_Invert: + // TODO + break; + case ActionType_UndoCrop: + // TODO + break; + case ActionType_Rotate: + // TODO + break; + default: + throw std::runtime_error("Action type not supported"); + } + return true; + } + +#if ORTHANC_ENABLE_QT==1 + QStoneMainWindow* CtPetDoseStructFusionApplication::CreateQtMainWindow() + { + return new CtPetDoseStructFusionMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this); + } +#endif + +#if ORTHANC_ENABLE_WASM==1 + void CtPetDoseStructFusionApplication::InitializeWasm() { + + AttachWidgetToWasmViewport("canvasThumbnails", thumbnailsLayout_); + AttachWidgetToWasmViewport("canvasMain", mainWidget_); + } +#endif + + +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/CtPetDoseStructFusionApplication.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/CtPetDoseStructFusionApplication.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,170 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + + /* + This header contains the command definitions for the sample applications + */ +#include "Applications/Samples/StoneSampleCommands_generated.hpp" +using namespace StoneSampleCommands; + +#include "Applications/IStoneApplication.h" + +#include "Framework/Layers/CircleMeasureTracker.h" +#include "Framework/Layers/LineMeasureTracker.h" +#include "Framework/Widgets/SliceViewerWidget.h" +#include "Framework/Widgets/LayoutWidget.h" +#include "Framework/Messages/IObserver.h" +#include "Framework/SmartLoader.h" + +#if ORTHANC_ENABLE_WASM==1 +#include "Platforms/Wasm/WasmPlatformApplicationAdapter.h" +#include "Platforms/Wasm/Defaults.h" +#endif + +#if ORTHANC_ENABLE_QT==1 +#include "Qt/CtPetDoseStructFusionMainWindow.h" +#endif + +#include <Core/Images/Font.h> +#include <Core/Logging.h> + +#include "ThumbnailInteractor.h" +#include "MainWidgetInteractor.h" +#include "AppStatus.h" +#include "Messages.h" + +using namespace OrthancStone; + + +namespace CtPetDoseStructFusion +{ + + class CtPetDoseStructFusionApplication + : public IStoneApplication + , public IObserver + , public IObservable + , public StoneSampleCommands::IHandler + { + public: + + struct StatusUpdatedMessage : public BaseMessage<CtPetDoseStructFusionMessageType_AppStatusUpdated> + { + const AppStatus& status_; + + StatusUpdatedMessage(const AppStatus& status) + : BaseMessage(), + status_(status) + { + } + }; + + private: + Tool currentTool_; + + std::auto_ptr<MainWidgetInteractor> mainWidgetInteractor_; + std::auto_ptr<ThumbnailInteractor> thumbnailInteractor_; + LayoutWidget* mainLayout_; + LayoutWidget* thumbnailsLayout_; + SliceViewerWidget* mainWidget_; + std::vector<SliceViewerWidget*> thumbnails_; + std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_; + std::map<std::string, Json::Value> seriesTags_; + unsigned int currentInstanceIndex_; + OrthancStone::WidgetViewport* wasmViewport1_; + OrthancStone::WidgetViewport* wasmViewport2_; + + IStatusBar* statusBar_; + std::auto_ptr<SmartLoader> smartLoader_; + + Orthanc::Font font_; + + public: + CtPetDoseStructFusionApplication(MessageBroker& broker) : + IObserver(broker), + IObservable(broker), + currentTool_(StoneSampleCommands::Tool_LineMeasure), + mainLayout_(NULL), + currentInstanceIndex_(0), + wasmViewport1_(NULL), + wasmViewport2_(NULL) + { + font_.LoadFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); + } + + virtual void Finalize() {} + virtual IWidget* GetCentralWidget() {return mainLayout_;} + + virtual void DeclareStartupOptions(boost::program_options::options_description& options); + virtual void Initialize(StoneApplicationContext* context, + IStatusBar& statusBar, + const boost::program_options::variables_map& parameters); + + void OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message); + + void OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message); + + void OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message); + + void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId); + + void SelectStudy(const std::string& studyId); + + void OnWidgetGeometryChanged(const SliceViewerWidget::GeometryChangedMessage& message); + + void SelectSeriesInMainViewport(const std::string& seriesId); + + + Tool GetCurrentTool() const + { + return currentTool_; + } + + const Orthanc::Font& GetFont() const + { + return font_; + } + + // ExecuteAction method was empty (its body was a single "TODO" comment) + virtual bool Handle(const SelectTool& value) ORTHANC_OVERRIDE; + virtual bool Handle(const Action& value) ORTHANC_OVERRIDE; + + template<typename T> + bool ExecuteCommand(const T& cmd) + { + std::string cmdStr = StoneSampleCommands::StoneSerialize(cmd); + return StoneSampleCommands::StoneDispatchToHandler(cmdStr, this); + } + + virtual std::string GetTitle() const {return "CtPetDoseStructFusion";} + +#if ORTHANC_ENABLE_WASM==1 + virtual void InitializeWasm(); +#endif + +#if ORTHANC_ENABLE_QT==1 + virtual QStoneMainWindow* CreateQtMainWindow(); +#endif + }; + + +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/MainWidgetInteractor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/MainWidgetInteractor.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,111 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "MainWidgetInteractor.h" + +#include "CtPetDoseStructFusionApplication.h" + +namespace CtPetDoseStructFusion { + + IWorldSceneMouseTracker* MainWidgetInteractor::CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + MouseButton button, + KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector<Touch>& displayTouches) + { + if (button == MouseButton_Left) + { + if (application_.GetCurrentTool() == Tool_LineMeasure) + { + return new LineMeasureTracker(statusBar, dynamic_cast<SliceViewerWidget&>(widget).GetSlice(), + x, y, 255, 0, 0, application_.GetFont()); + } + else if (application_.GetCurrentTool() == Tool_CircleMeasure) + { + return new CircleMeasureTracker(statusBar, dynamic_cast<SliceViewerWidget&>(widget).GetSlice(), + x, y, 255, 0, 0, application_.GetFont()); + } + else if (application_.GetCurrentTool() == Tool_Crop) + { + // TODO + } + else if (application_.GetCurrentTool() == Tool_Windowing) + { + // TODO + } + else if (application_.GetCurrentTool() == Tool_Zoom) + { + // TODO + } + else if (application_.GetCurrentTool() == Tool_Pan) + { + // TODO + } + } + return NULL; + } + + void MainWidgetInteractor::MouseOver(CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) + { + if (statusBar != NULL) + { + Vector p = dynamic_cast<SliceViewerWidget&>(widget).GetSlice().MapSliceToWorldCoordinates(x, y); + + char buf[64]; + sprintf(buf, "X = %.02f Y = %.02f Z = %.02f (in cm)", + p[0] / 10.0, p[1] / 10.0, p[2] / 10.0); + statusBar->SetMessage(buf); + } + } + + void MainWidgetInteractor::MouseWheel(WorldSceneWidget& widget, + MouseWheelDirection direction, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + } + + void MainWidgetInteractor::KeyPressed(WorldSceneWidget& widget, + KeyboardKeys key, + char keyChar, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + switch (keyChar) + { + case 's': + widget.FitContent(); + break; + + default: + break; + } + } +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/MainWidgetInteractor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/MainWidgetInteractor.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,76 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#pragma once + +#include "Framework/Widgets/IWorldSceneInteractor.h" + +using namespace OrthancStone; + +namespace CtPetDoseStructFusion { + + class CtPetDoseStructFusionApplication; + + class MainWidgetInteractor : public IWorldSceneInteractor + { + private: + CtPetDoseStructFusionApplication& application_; + + public: + MainWidgetInteractor(CtPetDoseStructFusionApplication& application) : + application_(application) + { + } + + /** + WorldSceneWidget: + */ + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + MouseButton button, + KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector<Touch>& displayTouches); + + virtual void MouseOver(CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar); + + virtual void MouseWheel(WorldSceneWidget& widget, + MouseWheelDirection direction, + KeyboardModifiers modifiers, + IStatusBar* statusBar); + + virtual void KeyPressed(WorldSceneWidget& widget, + KeyboardKeys key, + char keyChar, + KeyboardModifiers modifiers, + IStatusBar* statusBar); + }; + + +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Messages.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Messages.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,10 @@ +#pragma once + +namespace CtPetDoseStructFusion +{ + enum CtPetDoseStructFusionMessageType + { + CtPetDoseStructFusionMessageType_First = OrthancStone::MessageType_CustomMessage, + CtPetDoseStructFusionMessageType_AppStatusUpdated + }; +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,110 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "CtPetDoseStructFusionMainWindow.h" + +/** + * Don't use "ui_MainWindow.h" instead of <ui_MainWindow.h> below, as + * this makes CMake unable to detect when the UI file changes. + **/ +#include <ui_CtPetDoseStructFusionMainWindow.h> +#include "../CtPetDoseStructFusionApplication.h" + + +namespace CtPetDoseStructFusion +{ + + template<typename T, typename U> + bool ExecuteCommand(U* handler, const T& command) + { + std::string serializedCommand = StoneSerialize(command); + StoneDispatchToHandler(serializedCommand, handler); + } + + CtPetDoseStructFusionMainWindow::CtPetDoseStructFusionMainWindow( + OrthancStone::NativeStoneApplicationContext& context, + CtPetDoseStructFusionApplication& stoneApplication, + QWidget *parent) : + QStoneMainWindow(context, parent), + ui_(new Ui::CtPetDoseStructFusionMainWindow), + stoneApplication_(stoneApplication) + { + ui_->setupUi(this); + SetCentralStoneWidget(*ui_->cairoCentralWidget); + +#if QT_VERSION >= 0x050000 + connect(ui_->toolButtonCrop, &QToolButton::clicked, this, &CtPetDoseStructFusionMainWindow::cropClicked); + connect(ui_->pushButtonUndoCrop, &QToolButton::clicked, this, &CtPetDoseStructFusionMainWindow::undoCropClicked); + connect(ui_->toolButtonLine, &QToolButton::clicked, this, &CtPetDoseStructFusionMainWindow::lineClicked); + connect(ui_->toolButtonCircle, &QToolButton::clicked, this, &CtPetDoseStructFusionMainWindow::circleClicked); + connect(ui_->toolButtonWindowing, &QToolButton::clicked, this, &CtPetDoseStructFusionMainWindow::windowingClicked); + connect(ui_->pushButtonRotate, &QPushButton::clicked, this, &CtPetDoseStructFusionMainWindow::rotateClicked); + connect(ui_->pushButtonInvert, &QPushButton::clicked, this, &CtPetDoseStructFusionMainWindow::invertClicked); +#else + connect(ui_->toolButtonCrop, SIGNAL(clicked()), this, SLOT(cropClicked())); + connect(ui_->toolButtonLine, SIGNAL(clicked()), this, SLOT(lineClicked())); + connect(ui_->toolButtonCircle, SIGNAL(clicked()), this, SLOT(circleClicked())); + connect(ui_->toolButtonWindowing, SIGNAL(clicked()), this, SLOT(windowingClicked())); + connect(ui_->pushButtonUndoCrop, SIGNAL(clicked()), this, SLOT(undoCropClicked())); + connect(ui_->pushButtonRotate, SIGNAL(clicked()), this, SLOT(rotateClicked())); + connect(ui_->pushButtonInvert, SIGNAL(clicked()), this, SLOT(invertClicked())); +#endif + } + + CtPetDoseStructFusionMainWindow::~CtPetDoseStructFusionMainWindow() + { + delete ui_; + } + + void CtPetDoseStructFusionMainWindow::cropClicked() + { + stoneApplication_.ExecuteCommand(SelectTool(Tool_Crop)); + } + + void CtPetDoseStructFusionMainWindow::undoCropClicked() + { + stoneApplication_.ExecuteCommand(Action(ActionType_UndoCrop)); + } + + void CtPetDoseStructFusionMainWindow::lineClicked() + { + stoneApplication_.ExecuteCommand(SelectTool(Tool_LineMeasure)); + } + + void CtPetDoseStructFusionMainWindow::circleClicked() + { + stoneApplication_.ExecuteCommand(SelectTool(Tool_CircleMeasure)); + } + + void CtPetDoseStructFusionMainWindow::windowingClicked() + { + stoneApplication_.ExecuteCommand(SelectTool(Tool_Windowing)); + } + + void CtPetDoseStructFusionMainWindow::rotateClicked() + { + stoneApplication_.ExecuteCommand(Action(ActionType_Rotate)); + } + + void CtPetDoseStructFusionMainWindow::invertClicked() + { + stoneApplication_.ExecuteCommand(Action(ActionType_Invert)); + } +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,57 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ +#pragma once + +#include <Applications/Qt/QCairoWidget.h> +#include <Applications/Qt/QStoneMainWindow.h> + +namespace Ui +{ + class CtPetDoseStructFusionMainWindow; +} + +using namespace OrthancStone; + +namespace CtPetDoseStructFusion +{ + class CtPetDoseStructFusionApplication; + + class CtPetDoseStructFusionMainWindow : public QStoneMainWindow + { + Q_OBJECT + + private: + Ui::CtPetDoseStructFusionMainWindow* ui_; + CtPetDoseStructFusionApplication& stoneApplication_; + + public: + explicit CtPetDoseStructFusionMainWindow(OrthancStone::NativeStoneApplicationContext& context, CtPetDoseStructFusionApplication& stoneApplication, QWidget *parent = 0); + ~CtPetDoseStructFusionMainWindow(); + + private slots: + void cropClicked(); + void undoCropClicked(); + void rotateClicked(); + void windowingClicked(); + void lineClicked(); + void circleClicked(); + void invertClicked(); + }; +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.ui --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Qt/CtPetDoseStructFusionMainWindow.ui Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CtPetDoseStructFusionMainWindow</class> + <widget class="QMainWindow" name="CtPetDoseStructFusionMainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>634</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>300</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>500</width> + <height>300</height> + </size> + </property> + <property name="windowTitle"> + <string>Stone of Orthanc</string> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <widget class="QWidget" name="centralwidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <widget class="QCairoWidget" name="cairoCentralWidget"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>500</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="horizontalGroupBox"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>100</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>100</height> + </size> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QToolButton" name="toolButtonWindowing"> + <property name="text"> + <string>windowing</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButtonCrop"> + <property name="text"> + <string>crop</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButtonUndoCrop"> + <property name="text"> + <string>undo crop</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButtonLine"> + <property name="text"> + <string>line</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="toolButtonCircle"> + <property name="text"> + <string>circle</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButtonRotate"> + <property name="text"> + <string>rotate</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButtonInvert"> + <property name="text"> + <string>invert</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>22</height> + </rect> + </property> + <widget class="QMenu" name="menuTest"> + <property name="title"> + <string>Test</string> + </property> + </widget> + <addaction name="menuTest"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <customwidgets> + <customwidget> + <class>QCairoWidget</class> + <extends>QGraphicsView</extends> + <header location="global">QCairoWidget.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Qt/mainQt.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Qt/mainQt.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,14 @@ +#include "Applications/Qt/QtStoneApplicationRunner.h" + +#include "../CtPetDoseStructFusionApplication.h" +#include "Framework/Messages/MessageBroker.h" + + +int main(int argc, char* argv[]) +{ + OrthancStone::MessageBroker broker; + CtPetDoseStructFusion::CtPetDoseStructFusionApplication stoneApplication(broker); + + OrthancStone::QtStoneApplicationRunner qtAppRunner(broker, stoneApplication); + return qtAppRunner.Execute(argc, argv); +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/ThumbnailInteractor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/ThumbnailInteractor.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,46 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "ThumbnailInteractor.h" + +#include "CtPetDoseStructFusionApplication.h" + +namespace CtPetDoseStructFusion { + + IWorldSceneMouseTracker* ThumbnailInteractor::CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + MouseButton button, + KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector<Touch>& displayTouches) + { + if (button == MouseButton_Left) + { + statusBar->SetMessage("selected thumbnail " + widget.GetName()); + std::string seriesId = widget.GetName().substr(strlen("thumbnail-series-")); + application_.SelectSeriesInMainViewport(seriesId); + } + return NULL; + } +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/ThumbnailInteractor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/ThumbnailInteractor.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,77 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "Framework/Widgets/IWorldSceneInteractor.h" + +using namespace OrthancStone; + +namespace CtPetDoseStructFusion { + + class CtPetDoseStructFusionApplication; + + class ThumbnailInteractor : public IWorldSceneInteractor + { + private: + CtPetDoseStructFusionApplication& application_; + public: + ThumbnailInteractor(CtPetDoseStructFusionApplication& application) : + application_(application) + { + } + + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + MouseButton button, + KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector<Touch>& displayTouches); + + virtual void MouseOver(CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) + {} + + virtual void MouseWheel(WorldSceneWidget& widget, + MouseWheelDirection direction, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + {} + + virtual void KeyPressed(WorldSceneWidget& widget, + KeyboardKeys key, + char keyChar, + KeyboardModifiers modifiers, + IStatusBar* statusBar) + {} + + }; + + +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/CtPetDoseStructFusionWasmApplicationAdapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/CtPetDoseStructFusionWasmApplicationAdapter.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,51 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "CtPetDoseStructFusionWasmApplicationAdapter.h" + +namespace CtPetDoseStructFusion +{ + + CtPetDoseStructFusionWasmApplicationAdapter::CtPetDoseStructFusionWasmApplicationAdapter(MessageBroker &broker, CtPetDoseStructFusionApplication &application) + : WasmPlatformApplicationAdapter(broker, application), + viewerApplication_(application) + { + application.RegisterObserverCallback(new Callable<CtPetDoseStructFusionWasmApplicationAdapter, CtPetDoseStructFusionApplication::StatusUpdatedMessage>(*this, &CtPetDoseStructFusionWasmApplicationAdapter::OnStatusUpdated)); + } + + void CtPetDoseStructFusionWasmApplicationAdapter::OnStatusUpdated(const CtPetDoseStructFusionApplication::StatusUpdatedMessage &message) + { + Json::Value statusJson; + message.status_.ToJson(statusJson); + + Json::Value event; + event["event"] = "appStatusUpdated"; + event["data"] = statusJson; + + Json::StreamWriterBuilder builder; + std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter()); + std::ostringstream outputStr; + + writer->write(event, &outputStr); + + NotifyStatusUpdateFromCppToWebWithString(outputStr.str()); + } + +} // namespace CtPetDoseStructFusion \ No newline at end of file diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/CtPetDoseStructFusionWasmApplicationAdapter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/CtPetDoseStructFusionWasmApplicationAdapter.h Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,43 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#pragma once + +#include <string> +#include <Framework/Messages/IObserver.h> +#include <Platforms/Wasm/WasmPlatformApplicationAdapter.h> + +#include "../CtPetDoseStructFusionApplication.h" + +namespace CtPetDoseStructFusion { + + class CtPetDoseStructFusionWasmApplicationAdapter : public WasmPlatformApplicationAdapter + { + CtPetDoseStructFusionApplication& viewerApplication_; + + public: + CtPetDoseStructFusionWasmApplicationAdapter(MessageBroker& broker, CtPetDoseStructFusionApplication& application); + + private: + void OnStatusUpdated(const CtPetDoseStructFusionApplication::StatusUpdatedMessage& message); + + }; + +} \ No newline at end of file diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/ct-pet-dose-struct-fusion.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/ct-pet-dose-struct-fusion.html Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,43 @@ +<!doctype html> + +<html lang="us"> + <head> + <meta charset="utf-8" /> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + + <!-- Disable pinch zoom on mobile devices --> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> + <meta name="HandheldFriendly" content="true" /> + + <title>Simple Viewer</title> + <link href="styles.css" rel="stylesheet" /> + +<body> + <div id="breadcrumb"> + <span id="label-patient-id"></span> + <span id="label-study-description"></span> + <span id="label-series-description"></span> + </div> + <div style="height: calc(100% - 50px)"> + <div style="width: 20%; height: 100%; display: inline-block"> + <canvas id="canvasThumbnails"></canvas> + </div> + <div style="width: 70%; height: 100%; display: inline-block"> + <canvas id="canvasMain"></canvas> + </div> + </div> + <div id="toolbox" style="height: 50px"> + <button tool-selector="line-measure" class="tool-selector">line</button> + <button tool-selector="circle-measure" class="tool-selector">circle</button> + <button tool-selector="crop" class="tool-selector">crop</button> + <button tool-selector="windowing" class="tool-selector">windowing</button> + <button tool-selector="zoom" class="tool-selector">zoom</button> + <button tool-selector="pan" class="tool-selector">pan</button> + <button action-trigger="rotate-left" class="action-trigger">rotate left</button> + <button action-trigger="rotate-right" class="action-trigger">rotate right</button> + <button action-trigger="invert" class="action-trigger">invert</button> + </div> + <script type="text/javascript" src="app-ct-dose-struct-fusion.js"></script> +</body> + +</html> \ No newline at end of file diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/ct-pet-dose-struct-fusion.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/ct-pet-dose-struct-fusion.ts Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,81 @@ +import wasmApplicationRunner = require('../../../../Platforms/Wasm/wasm-application-runner'); + +wasmApplicationRunner.InitializeWasmApplication("OrthancStoneCtPetDoseStructFusion", "/orthanc"); + +function SelectTool(toolName: string) { + var command = { + command: "selectTool:" + toolName, + commandType: "generic-no-arg-command", + args: { + } + }; + wasmApplicationRunner.SendCommandToStoneApplication(JSON.stringify(command)); +} + +function PerformAction(actionName: string) { + var command = { + command: "action:" + actionName, + commandType: "generic-no-arg-command", + args: { + } + }; + wasmApplicationRunner.SendCommandToStoneApplication(JSON.stringify(command)); +} + +class CtPetDoseStructFusionUI { + + private _labelPatientId: HTMLSpanElement; + private _labelStudyDescription: HTMLSpanElement; + + public constructor() { + // install "SelectTool" handlers + document.querySelectorAll("[tool-selector]").forEach((e) => { + (e as HTMLButtonElement).addEventListener("click", () => { + SelectTool(e.attributes["tool-selector"].value); + }); + }); + + // install "PerformAction" handlers + document.querySelectorAll("[action-trigger]").forEach((e) => { + (e as HTMLButtonElement).addEventListener("click", () => { + PerformAction(e.attributes["action-trigger"].value); + }); + }); + + // connect all ui elements to members + this._labelPatientId = document.getElementById("label-patient-id") as HTMLSpanElement; + this._labelStudyDescription = document.getElementById("label-study-description") as HTMLSpanElement; + } + + public onAppStatusUpdated(status: any) { + this._labelPatientId.innerText = status["patientId"]; + this._labelStudyDescription.innerText = status["studyDescription"]; + // this.highlighThumbnail(status["currentInstanceIdInMainViewport"]); + } + +} + +var ui = new CtPetDoseStructFusionUI(); + +// 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 UpdateWebApplicationWithString(statusUpdateMessageString: string) { + console.log("updating web application with string: ", statusUpdateMessageString); + let statusUpdateMessage = JSON.parse(statusUpdateMessageString); + + if ("event" in statusUpdateMessage) { + let eventName = statusUpdateMessage["event"]; + if (eventName == "appStatusUpdated") { + ui.onAppStatusUpdated(statusUpdateMessage["data"]); + } + } +} + +function UpdateWebApplicationWithSerializedMessage(statusUpdateMessageString: string) { + console.log("updating web application with serialized message: ", statusUpdateMessageString); + console.log("<not supported in the simple viewer!>"); +} + +// make it available to other js scripts in the application +(<any> window).UpdateWebApplicationWithString = UpdateWebApplicationWithString; +(<any> window).UpdateWebApplicationWithSerializedMessage = UpdateWebApplicationWithSerializedMessage; diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/mainWasm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/mainWasm.cpp Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,38 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include "Platforms/Wasm/WasmWebService.h" +#include "Platforms/Wasm/WasmViewport.h" + +#include <emscripten/emscripten.h> + +#include "../CtPetDoseStructFusionApplication.h" +#include "CtPetDoseStructFusionWasmApplicationAdapter.h" + + +OrthancStone::IStoneApplication* CreateUserApplication(OrthancStone::MessageBroker& broker) { + + return new CtPetDoseStructFusion::CtPetDoseStructFusionApplication(broker); +} + +OrthancStone::WasmPlatformApplicationAdapter* CreateWasmApplicationAdapter(OrthancStone::MessageBroker& broker, IStoneApplication* application) +{ + return new CtPetDoseStructFusion::CtPetDoseStructFusionWasmApplicationAdapter(broker, *(dynamic_cast<CtPetDoseStructFusion::CtPetDoseStructFusionApplication*>(application))); +} diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/styles.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/styles.css Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,54 @@ +html, body { + width: 100%; + height: 100%; + margin: 0px; + border: 0; + overflow: hidden; /* Disable scrollbars */ + display: block; /* No floating content on sides */ + background-color: black; + color: white; + font-family: Arial, Helvetica, sans-serif; +} + +canvas { + left:0px; + top:0px; +} + +#canvas-group { + padding:5px; + background-color: grey; +} + +#status-group { + padding:5px; +} + +#worklist-group { + padding:5px; +} + +.vsol-button { + height: 40px; +} + +#thumbnails-group ul li { + display: inline; + list-style: none; +} + +.thumbnail { + width: 100px; + height: 100px; + padding: 3px; +} + +.thumbnail-selected { + border-width: 1px; + border-color: red; + border-style: solid; +} + +#template-thumbnail-li { + display: none !important; +} \ No newline at end of file diff -r 9d124a81c34a -r 7428c5dfa5df Applications/Samples/CtPetDoseStructFusion/Wasm/tsconfig-ct-pet-dose-struct-fusion.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/CtPetDoseStructFusion/Wasm/tsconfig-ct-pet-dose-struct-fusion.json Tue Mar 19 16:29:07 2019 +0100 @@ -0,0 +1,9 @@ +{ + "extends" : "../../Web/tsconfig-samples", + "compilerOptions": { + }, + "include" : [ + "ct-dose-struct-fusion.ts", + "../../build-wasm/ApplicationCommands_generated.ts" + ] +}