diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp index fe0fb8db2b..1e9d6044ee 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.cpp @@ -1,186 +1,195 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "SimpleRenderWindowView.h" #include #include "org_mitk_example_gui_customviewer_views_Activator.h" #include #include #include #include #include #include /** * \brief Helper class adapted from QmitkAbstractRenderEditor by defining the correct plugin context. * * This helper class adapted from QmitkAbstractRenderEditor provides the rendering manager interface. */ // //! [SimpleRenderWindowViewHelper] class AbstractRenderWindowViewPrivate { public: AbstractRenderWindowViewPrivate() : m_RenderingManagerInterface(mitk::MakeRenderingManagerInterface(mitk::RenderingManager::GetInstance())), m_PrefServiceTracker(org_mitk_example_gui_customviewer_views_Activator::GetPluginContext()) // //! [SimpleRenderWindowViewHelper] { m_PrefServiceTracker.open(); } ~AbstractRenderWindowViewPrivate() { delete m_RenderingManagerInterface; } mitk::IRenderingManager *m_RenderingManagerInterface; ctkServiceTracker m_PrefServiceTracker; berry::IBerryPreferences::Pointer m_Prefs; }; const std::string SimpleRenderWindowView::VIEW_ID = "org.mitk.customviewer.views.simplerenderwindowview"; SimpleRenderWindowView::SimpleRenderWindowView() : m_RenderWindow(nullptr), d(new AbstractRenderWindowViewPrivate) { } SimpleRenderWindowView::~SimpleRenderWindowView() { } QmitkRenderWindow *SimpleRenderWindowView::GetActiveQmitkRenderWindow() const { return m_RenderWindow; } QHash SimpleRenderWindowView::GetRenderWindows() const { QHash wnds; wnds.insert("transversal", m_RenderWindow); return wnds; } QHash SimpleRenderWindowView::GetQmitkRenderWindows() const { QHash wnds; wnds.insert("transversal", m_RenderWindow); return wnds; } QmitkRenderWindow *SimpleRenderWindowView::GetRenderWindow(const QString &id) const { if (id == "transversal") { return m_RenderWindow; } return nullptr; } QmitkRenderWindow *SimpleRenderWindowView::GetQmitkRenderWindow(const QString &id) const { if (id == "transversal") { return m_RenderWindow; } return nullptr; } +QmitkRenderWindow *SimpleRenderWindowView::GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection &viewDirection) const +{ + if (viewDirection == mitk::BaseRenderer::ViewDirection::AXIAL) + { + return m_RenderWindow; + } + return 0; +} + mitk::Point3D SimpleRenderWindowView::GetSelectedPosition(const QString & /*id*/) const { const mitk::PlaneGeometry *pg = m_RenderWindow->GetSliceNavigationController()->GetCurrentPlaneGeometry(); if (pg) { return pg->GetCenter(); } else { return mitk::Point3D(); } } void SimpleRenderWindowView::SetSelectedPosition(const mitk::Point3D &, const QString &) { } void SimpleRenderWindowView::EnableDecorations(bool enable, const QStringList &decorations) { if (decorations.isEmpty() || decorations.contains(DECORATION_MENU)) { m_RenderWindow->ActivateMenuWidget(enable); } } bool SimpleRenderWindowView::IsDecorationEnabled(const QString &decoration) const { if (decoration == DECORATION_MENU) { return m_RenderWindow->GetActivateMenuWidgetFlag(); } return false; } QStringList SimpleRenderWindowView::GetDecorations() const { QStringList decorations; decorations << DECORATION_MENU; return decorations; } void SimpleRenderWindowView::SetFocus() { m_RenderWindow->setFocus(); } // //! [SimpleRenderWindowViewCreatePartControl] void SimpleRenderWindowView::CreateQtPartControl(QWidget *parent) { QVBoxLayout *layout = new QVBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); m_RenderWindow = new QmitkRenderWindow(parent); layout->addWidget(m_RenderWindow); mitk::DataStorage::Pointer ds = this->GetDataStorage(); m_RenderWindow->GetRenderer()->SetDataStorage(ds); this->RequestUpdate(); } // //! [SimpleRenderWindowViewCreatePartControl] mitk::IRenderingManager *SimpleRenderWindowView::GetRenderingManager() const { // we use the global rendering manager here. This should maybe replaced // by a local one, managing only the render windows specific for the view return d->m_RenderingManagerInterface; } void SimpleRenderWindowView::RequestUpdate(mitk::RenderingManager::RequestType requestType) { if (GetRenderingManager()) GetRenderingManager()->RequestUpdateAll(requestType); } void SimpleRenderWindowView::ForceImmediateUpdate(mitk::RenderingManager::RequestType requestType) { if (GetRenderingManager()) GetRenderingManager()->ForceImmediateUpdateAll(requestType); } mitk::SliceNavigationController *SimpleRenderWindowView::GetTimeNavigationController() const { if (GetRenderingManager()) return GetRenderingManager()->GetTimeNavigationController(); return nullptr; } diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h index 7770aca353..c3f1a40cdd 100644 --- a/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h +++ b/Examples/Plugins/org.mitk.example.gui.customviewer.views/src/internal/SimpleRenderWindowView.h @@ -1,147 +1,146 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef SimpleRenderWindowView_H_ #define SimpleRenderWindowView_H_ #include #include #include class QmitkRenderWindow; class AbstractRenderWindowViewPrivate; /** * \brief A view class suited for the ViewerPerspective within the custom viewer plug-in. * * This view class contributes data node rendering functionality to the ViewerPerspective. * Being a subclass of QmitkAbstractView, this class yields access to the data storage and * thus is interconnected with the mitk::QmitkDataManagerView present in the same perspective. * As a subclass of mitk::IRenderWindowPart, this class provides an instance of QmitkRenderWindow. * A SimpleRenderWindowView instance is part of the ViewerPerspective for data visualization. */ // //! [SimpleRenderWindowViewDeclaration] class SimpleRenderWindowView : public QmitkAbstractView, public mitk::IRenderWindowPart // //! [SimpleRenderWindowViewDeclaration] { Q_OBJECT public: /** * Standard constructor. */ SimpleRenderWindowView(); ~SimpleRenderWindowView() override; /** * String based view identifier. */ static const std::string VIEW_ID; berryObjectMacro(SimpleRenderWindowView); // ------------------- mitk::IRenderWindowPart ---------------------- /** * \see mitk::IRenderWindowPart::GetActiveQmitkRenderWindow() */ QmitkRenderWindow *GetActiveQmitkRenderWindow() const override; - /** - * \see mitk::IRenderWindowPart::GetRenderWindows() - */ QHash GetRenderWindows() const; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindows() */ QHash GetQmitkRenderWindows() const override; - /** - * \see mitk::IRenderWindowPart::GetRenderWindow(QString) - */ QmitkRenderWindow *GetRenderWindow(const QString &id) const; /** * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(QString) */ QmitkRenderWindow *GetQmitkRenderWindow(const QString &id) const override; + /** + * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(mitk::BaseRenderer::ViewDirection) + */ + QmitkRenderWindow *GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection &viewDirection) const override; + /** * \see mitk::IRenderWindowPart::GetSelectionPosition() */ mitk::Point3D GetSelectedPosition(const QString &id = QString()) const override; /** * \see mitk::IRenderWindowPart::SetSelectedPosition() */ void SetSelectedPosition(const mitk::Point3D &pos, const QString &id = QString()) override; /** * \see mitk::IRenderWindowPart::EnableDecorations() */ void EnableDecorations(bool enable, const QStringList &decorations = QStringList()) override; /** * \see mitk::IRenderWindowPart::IsDecorationEnabled() */ bool IsDecorationEnabled(const QString &decoration) const override; /** * \see mitk::IRenderWindowPart::GetDecorations() */ QStringList GetDecorations() const override; /** * \see mitk::QmitkAbstractRenderEditor::GetRenderingManager() */ mitk::IRenderingManager *GetRenderingManager() const override; /** * \see mitk::QmitkAbstractRenderEditor::RequestUpdate() */ void RequestUpdate( mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) override; /** * \see mitk::QmitkAbstractRenderEditor::ForceImmediateUpdate() */ void ForceImmediateUpdate(mitk::RenderingManager::RequestType) override; /** * \see mitk::QmitkAbstractRenderEditor::GetTimeNavigationController() */ mitk::SliceNavigationController *GetTimeNavigationController() const override; protected: void SetFocus() override; /** * Creates the QmitkRenderWindow whose renderer is being connected to the view's data storage. */ void CreateQtPartControl(QWidget *parent) override; private: /** * The view's render window. */ QmitkRenderWindow *m_RenderWindow; QScopedPointer d; }; #endif /*SimpleRenderWindowView_H_*/ diff --git a/Examples/Tutorial/Step8/Step8.cpp b/Examples/Tutorial/Step8/Step8.cpp index 75c6201ebd..e660294d2b 100644 --- a/Examples/Tutorial/Step8/Step8.cpp +++ b/Examples/Tutorial/Step8/Step8.cpp @@ -1,81 +1,79 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "Step8.h" +#include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "mitkRenderingManager.h" #include #include //##Documentation //## @brief As Step6, but with QmitkStdMultiWidget as widget Step8::Step8(int argc, char *argv[], QWidget *parent) : Step6(argc, argv, parent) { } void Step8::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget *viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout *hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); //************************************************************************* // Part Ia: create and initialize QmitkStdMultiWidget //************************************************************************* QmitkStdMultiWidget *multiWidget = new QmitkStdMultiWidget(viewParent); hlayout->addWidget(multiWidget); // Tell the multiWidget which DataStorage to render multiWidget->SetDataStorage(m_DataStorage); // Initialize views as axial, sagittal, coronar (from // top-left to bottom) auto geo = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); // Initialize bottom-right view as 3D view multiWidget->GetRenderWindow4()->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); - // Enable standard handler for levelwindow-slider - multiWidget->EnableStandardLevelWindow(); - // Add the displayed views to the DataStorage to see their positions in 2D and 3D multiWidget->AddDisplayPlaneSubTree(); multiWidget->AddPlanesToDataStorage(); multiWidget->SetWidgetPlanesVisibility(true); //************************************************************************* // Part II: Setup standard interaction with the mouse //************************************************************************* } /** \example Step8.cpp */ diff --git a/Modules/Core/include/mitkBaseRenderer.h b/Modules/Core/include/mitkBaseRenderer.h index 47c2993697..dd9ed0707a 100644 --- a/Modules/Core/include/mitkBaseRenderer.h +++ b/Modules/Core/include/mitkBaseRenderer.h @@ -1,556 +1,566 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #define BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #include "mitkCameraRotationController.h" #include "mitkDataStorage.h" #include "mitkPlaneGeometry.h" #include "mitkPlaneGeometryData.h" #include "mitkSliceNavigationController.h" #include "mitkTimeGeometry.h" #include "mitkBindDispatcherInteractor.h" #include "mitkDispatcher.h" #include #include #include #include // DEPRECATED #include namespace mitk { class NavigationController; class SliceNavigationController; class CameraRotationController; class CameraController; class DataStorage; class Mapper; class BaseLocalStorageHandler; class KeyEvent; //##Documentation //## @brief Organizes the rendering process //## //## Organizes the rendering process. A Renderer contains a reference to a //## DataStorage and asks the mappers of the data objects to render //## the data into the renderwindow it is associated to. //## //## \#Render() checks if rendering is currently allowed by calling //## RenderWindow::PrepareRendering(). Initialization of a rendering context //## can also be performed in this method. //## //## The actual rendering code has been moved to \#Repaint() //## Both \#Repaint() and \#Update() are declared protected now. //## //## Note: Separation of the Repaint and Update processes (rendering vs //## creating a vtk prop tree) still needs to be worked on. The whole //## rendering process also should be reworked to use VTK based classes for //## both 2D and 3D rendering. //## @ingroup Renderer class MITKCORE_EXPORT BaseRenderer : public itk::Object { public: /** \brief This rendering mode enumeration is specified at various constructors * of the Renderer and RenderWindow classes, which autoconfigures the * respective VTK objects. This has to be done at construction time because later * configuring turns out to be not working on most platforms. */ struct RenderingMode { enum Type { Standard = 0 }; }; typedef std::map BaseRendererMapType; static BaseRendererMapType baseRendererMap; static BaseRenderer *GetInstance(vtkRenderWindow *renWin); static void AddInstance(vtkRenderWindow *renWin, BaseRenderer *baseRenderer); static void RemoveInstance(vtkRenderWindow *renWin); static BaseRenderer *GetByName(const std::string &name); static vtkRenderWindow *GetRenderWindowByName(const std::string &name); #pragma GCC visibility push(default) itkEventMacro(RendererResetEvent, itk::AnyEvent); #pragma GCC visibility pop /** Standard class typedefs. */ mitkClassMacroItkParent(BaseRenderer, itk::Object); BaseRenderer(const char *name = nullptr, vtkRenderWindow *renWin = nullptr, mitk::RenderingManager *rm = nullptr, RenderingMode::Type mode = RenderingMode::Standard); //##Documentation - //## @brief MapperSlotId defines which kind of mapper (e.g., 2D or 3D) shoud be used. + //## @brief MapperSlotId defines which kind of mapper (e.g. 2D or 3D) should be used. typedef int MapperSlotId; enum StandardMapperSlot { Standard2D = 1, Standard3D = 2 }; + //##Documentation + //## @brief Possible view directions for render windows. + enum class ViewDirection + { + AXIAL = 0, + SAGITTAL, + CORONAL, + THREE_D + }; + virtual void SetDataStorage(DataStorage *storage); ///< set the datastorage that will be used for rendering //##Documentation //## return the DataStorage that is used for rendering virtual DataStorage::Pointer GetDataStorage() const { return m_DataStorage.GetPointer(); } //##Documentation //## @brief Access the RenderWindow into which this renderer renders. vtkRenderWindow *GetRenderWindow() const { return m_RenderWindow; } vtkRenderer *GetVtkRenderer() const { return m_VtkRenderer; } //##Documentation //## @brief Returns the Dispatcher which handles Events for this BaseRenderer Dispatcher::Pointer GetDispatcher() const; //##Documentation //## @brief Default mapper id to use. static const MapperSlotId defaultMapper; //##Documentation //## @brief Do the rendering and flush the result. virtual void Paint(); //##Documentation //## @brief Initialize the RenderWindow. Should only be called from RenderWindow. virtual void Initialize(); //##Documentation //## @brief Called to inform the renderer that the RenderWindow has been resized. virtual void Resize(int w, int h); //##Documentation //## @brief Initialize the renderer with a RenderWindow (@a renderwindow). virtual void InitRenderer(vtkRenderWindow *renderwindow); //##Documentation //## @brief Set the initial size. Called by RenderWindow after it has become //## visible for the first time. virtual void InitSize(int w, int h); //##Documentation //## @brief Draws a point on the widget. //## Should be used during conferences to show the position of the remote mouse virtual void DrawOverlayMouse(Point2D &p2d); //##Documentation //## @brief Set/Get the WorldGeometry (m_WorldGeometry) for 3D and 2D rendering, that describing the //## (maximal) area to be rendered. //## //## Depending of the type of the passed BaseGeometry more or less information can be extracted: //## \li if it is a PlaneGeometry (which is a sub-class of BaseGeometry), m_CurrentWorldPlaneGeometry is //## also set to point to it. m_WorldTimeGeometry is set to nullptr. //## \li if it is a TimeGeometry, m_WorldTimeGeometry is also set to point to it. //## If m_WorldTimeGeometry contains instances of SlicedGeometry3D, m_CurrentWorldPlaneGeometry is set to //## one of geometries stored in the SlicedGeometry3D according to the value of m_Slice; otherwise //## a PlaneGeometry describing the top of the bounding-box of the BaseGeometry is set as the //## m_CurrentWorldPlaneGeometry. //## \li otherwise a PlaneGeometry describing the top of the bounding-box of the BaseGeometry //## is set as the m_CurrentWorldPlaneGeometry. m_WorldTimeGeometry is set to nullptr. //## @todo add calculation of PlaneGeometry describing the top of the bounding-box of the BaseGeometry //## when the passed BaseGeometry is not sliced. //## \sa m_WorldGeometry //## \sa m_WorldTimeGeometry //## \sa m_CurrentWorldPlaneGeometry virtual void SetWorldGeometry3D(const BaseGeometry *geometry); virtual void SetWorldTimeGeometry(const mitk::TimeGeometry *geometry); /** * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void SetWorldGeometry3D(TimeSlicedGeometry *geometry)); itkGetConstObjectMacro(WorldTimeGeometry, TimeGeometry) //##Documentation //## @brief Get the current 3D-worldgeometry (m_CurrentWorldGeometry) used for 3D-rendering itkGetConstObjectMacro(CurrentWorldGeometry, BaseGeometry) //##Documentation //## @brief Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering itkGetConstObjectMacro(CurrentWorldPlaneGeometry, PlaneGeometry) /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometry */ DEPRECATED(const PlaneGeometry *GetCurrentWorldGeometry2D()) { return GetCurrentWorldPlaneGeometry(); }; //##Documentation //## Calculates the bounds of the DataStorage (if it contains any valid data), //## creates a geometry from these bounds and sets it as world geometry of the renderer. //## //## Call this method to re-initialize the renderer to the current DataStorage //## (e.g. after loading an additional dataset), to ensure that the view is //## aligned correctly. //## \warn This is not implemented yet. virtual bool SetWorldGeometryToDataStorageBounds() { return false; } //##Documentation //## @brief Set/Get m_Slice which defines together with m_TimeStep the 2D geometry //## stored in m_WorldTimeGeometry used as m_CurrentWorldPlaneGeometry //## //## \sa m_Slice virtual void SetSlice(unsigned int slice); itkGetConstMacro(Slice, unsigned int) //##Documentation //## @brief Set/Get m_TimeStep which defines together with m_Slice the 2D geometry //## stored in m_WorldTimeGeometry used as m_CurrentWorldPlaneGeometry //## //## \sa m_TimeStep virtual void SetTimeStep(unsigned int timeStep); itkGetConstMacro(TimeStep, unsigned int) //##Documentation //## @brief Get the time-step of a BaseData object which //## exists at the time of the currently displayed content //## //## Returns -1 or mitk::BaseData::m_TimeSteps if there //## is no data at the current time. //## \sa GetTimeStep, m_TimeStep int GetTimeStep(const BaseData *data) const; //##Documentation //## @brief Get the time in ms of the currently displayed content //## //## \sa GetTimeStep, m_TimeStep ScalarType GetTime() const; //##Documentation //## @brief SetWorldGeometry is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySendEvent virtual void SetGeometry(const itk::EventObject &geometrySliceEvent); //##Documentation //## @brief UpdateWorldGeometry is called to re-read the 2D geometry from the //## slice navigation controller virtual void UpdateGeometry(const itk::EventObject &geometrySliceEvent); //##Documentation //## @brief SetSlice is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySliceEvent virtual void SetGeometrySlice(const itk::EventObject &geometrySliceEvent); //##Documentation //## @brief SetTimeStep is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometryTimeEvent virtual void SetGeometryTime(const itk::EventObject &geometryTimeEvent); //##Documentation //## @brief Get a DataNode pointing to a data object containing the current 2D-worldgeometry // m_CurrentWorldPlaneGeometry (for 2D rendering) itkGetObjectMacro(CurrentWorldPlaneGeometryNode, DataNode) /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometryNode */ DEPRECATED(DataNode *GetCurrentWorldGeometry2DNode()) { return GetCurrentWorldPlaneGeometryNode(); }; //##Documentation //## @brief Sets timestamp of CurrentWorldPlaneGeometry and forces so reslicing in that renderwindow void SendUpdateSlice(); //##Documentation //## @brief Get timestamp of last call of SetCurrentWorldPlaneGeometry unsigned long GetCurrentWorldPlaneGeometryUpdateTime() { return m_CurrentWorldPlaneGeometryUpdateTime; } /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometryUpdateTime */ DEPRECATED(unsigned long GetCurrentWorldGeometry2DUpdateTime()) { return GetCurrentWorldPlaneGeometryUpdateTime(); }; //##Documentation //## @brief Get timestamp of last change of current TimeStep unsigned long GetTimeStepUpdateTime() { return m_TimeStepUpdateTime; } //##Documentation //## @brief Perform a picking: find the x,y,z world coordinate of a //## display x,y coordinate. //## @warning Has to be overwritten in subclasses for the 3D-case. //## //## Implemented here only for 2D-rendering virtual void PickWorldPoint(const Point2D &diplayPosition, Point3D &worldPosition) const = 0; /** \brief Determines the object (mitk::DataNode) closest to the current * position by means of picking * * \warning Implementation currently empty for 2D rendering; intended to be * implemented for 3D renderers */ virtual DataNode *PickObject(const Point2D & /*displayPosition*/, Point3D & /*worldPosition*/) const { return nullptr; } //##Documentation //## @brief Get the MapperSlotId to use. itkGetMacro(MapperID, MapperSlotId) itkGetConstMacro(MapperID, MapperSlotId) //##Documentation //## @brief Set the MapperSlotId to use. itkSetMacro(MapperID, MapperSlotId) virtual int *GetSize() const; virtual int *GetViewportSize() const; void SetSliceNavigationController(SliceNavigationController *SlicenavigationController); itkGetObjectMacro(CameraController, CameraController) itkGetObjectMacro(SliceNavigationController, SliceNavigationController) itkGetObjectMacro(CameraRotationController, CameraRotationController) itkGetMacro(EmptyWorldGeometry, bool) //##Documentation //## @brief Tells if the displayed region is shifted and rescaled if the render window is resized. itkGetMacro(KeepDisplayedRegion, bool) //##Documentation //## @brief Tells if the displayed region should be shifted and rescaled if the render window is resized. itkSetMacro(KeepDisplayedRegion, bool) //##Documentation //## @brief get the name of the Renderer //## @note const char *GetName() const { return m_Name.c_str(); } //##Documentation //## @brief get the x_size of the RendererWindow //## @note int GetSizeX() const { return GetSize()[0]; } //##Documentation //## @brief get the y_size of the RendererWindow //## @note int GetSizeY() const { return GetSize()[1]; } const double *GetBounds() const; void RequestUpdate(); void ForceImmediateUpdate(); /** Returns number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int GetNumberOfVisibleLODEnabledMappers() const; ///** //* \brief Setter for the RenderingManager that handles this instance of BaseRenderer //*/ // void SetRenderingManager( mitk::RenderingManager* ); /** * \brief Getter for the RenderingManager that handles this instance of BaseRenderer */ virtual mitk::RenderingManager *GetRenderingManager() const; //##Documentation //## @brief This method converts a display point to the 3D world index //## using the geometry of the renderWindow. void DisplayToWorld(const Point2D &displayPoint, Point3D &worldIndex) const; //##Documentation //## @brief This method converts a display point to the 2D world index, mapped onto the display plane //## using the geometry of the renderWindow. void DisplayToPlane(const Point2D &displayPoint, Point2D &planePointInMM) const; //##Documentation //## @brief This method converts a 3D world index to the display point //## using the geometry of the renderWindow. void WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const; //##Documentation //## @brief This method converts a 3D world index to the point on the viewport //## using the geometry of the renderWindow. void WorldToView(const Point3D &worldIndex, Point2D &viewPoint) const; //##Documentation //## @brief This method converts a 2D plane coordinate to the display point //## using the geometry of the renderWindow. void PlaneToDisplay(const Point2D &planePointInMM, Point2D &displayPoint) const; //##Documentation //## @brief This method converts a 2D plane coordinate to the point on the viewport //## using the geometry of the renderWindow. void PlaneToView(const Point2D &planePointInMM, Point2D &viewPoint) const; double GetScaleFactorMMPerDisplayUnit() const; Point2D GetDisplaySizeInMM() const; Point2D GetViewportSizeInMM() const; Point2D GetOriginInMM() const; itkGetConstMacro(ConstrainZoomingAndPanning, bool) virtual void SetConstrainZoomingAndPanning(bool constrain); /** * \brief Provides (1) world coordinates for a given mouse position and (2) * translates mousePosition to Display coordinates * \deprecated Map2DRendererPositionTo3DWorldPosition is deprecated. Please use DisplayToWorld instead. */ DEPRECATED(virtual Point3D Map2DRendererPositionTo3DWorldPosition(const Point2D &mousePosition) const); protected: ~BaseRenderer() override; //##Documentation //## @brief Call update of all mappers. To be implemented in subclasses. virtual void Update() = 0; vtkRenderWindow *m_RenderWindow; vtkRenderer *m_VtkRenderer; //##Documentation //## @brief MapperSlotId to use. Defines which kind of mapper (e.g., 2D or 3D) shoud be used. MapperSlotId m_MapperID; //##Documentation //## @brief The DataStorage that is used for rendering. DataStorage::Pointer m_DataStorage; //##Documentation //## @brief The RenderingManager that manages this instance RenderingManager::Pointer m_RenderingManager; //##Documentation //## @brief Timestamp of last call of Update(). unsigned long m_LastUpdateTime; //##Documentation //## @brief CameraController for 3D rendering //## @note preliminary. itk::SmartPointer m_CameraController; SliceNavigationController::Pointer m_SliceNavigationController; CameraRotationController::Pointer m_CameraRotationController; //##Documentation //## @brief Sets m_CurrentWorldPlaneGeometry virtual void SetCurrentWorldPlaneGeometry(const PlaneGeometry *geometry2d); /** * \deprecatedSince{2014_10} Please use SetCurrentWorldPlaneGeometry */ DEPRECATED(void SetCurrentWorldGeometry2D(PlaneGeometry *geometry2d)) { SetCurrentWorldPlaneGeometry(geometry2d); }; //##Documentation //## @brief Sets m_CurrentWorldGeometry virtual void SetCurrentWorldGeometry(const BaseGeometry *geometry); private: //##Documentation //## m_WorldTimeGeometry is set by SetWorldGeometry if the passed BaseGeometry is a //## TimeGeometry (or a sub-class of it). If it contains instances of SlicedGeometry3D, //## m_Slice and m_TimeStep (set via SetSlice and SetTimeStep, respectively) define //## which 2D geometry stored in m_WorldTimeGeometry (if available) //## is used as m_CurrentWorldPlaneGeometry. //## \sa m_CurrentWorldPlaneGeometry TimeGeometry::ConstPointer m_WorldTimeGeometry; //##Documentation //## Pointer to the current 3D-worldgeometry. BaseGeometry::ConstPointer m_CurrentWorldGeometry; //##Documentation //## Pointer to the current 2D-worldgeometry. The 2D-worldgeometry //## describes the maximal area (2D manifold) to be rendered in case we //## are doing 2D-rendering. //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). PlaneGeometry::Pointer m_CurrentWorldPlaneGeometry; //##Documentation //## Defines together with m_Slice which 2D geometry stored in m_WorldTimeGeometry //## is used as m_CurrentWorldPlaneGeometry: m_WorldTimeGeometry->GetPlaneGeometry(m_Slice, m_TimeStep). //## \sa m_WorldTimeGeometry unsigned int m_Slice; //##Documentation //## Defines together with m_TimeStep which 2D geometry stored in m_WorldTimeGeometry //## is used as m_CurrentWorldPlaneGeometry: m_WorldTimeGeometry->GetPlaneGeometry(m_Slice, m_TimeStep). //## \sa m_WorldTimeGeometry unsigned int m_TimeStep; //##Documentation //## @brief timestamp of last call of SetWorldGeometry itk::TimeStamp m_CurrentWorldPlaneGeometryUpdateTime; //##Documentation //## @brief timestamp of last change of the current time step itk::TimeStamp m_TimeStepUpdateTime; //##Documentation //## @brief Helper class which establishes connection between Interactors and Dispatcher via a common DataStorage. BindDispatcherInteractor *m_BindDispatcherInteractor; //##Documentation //## @brief Tells if the displayed region should be shifted or rescaled if the render window is resized. bool m_KeepDisplayedRegion; protected: void PrintSelf(std::ostream &os, itk::Indent indent) const override; //##Documentation //## Data object containing the m_CurrentWorldPlaneGeometry defined above. PlaneGeometryData::Pointer m_CurrentWorldPlaneGeometryData; //##Documentation //## DataNode objects containing the m_CurrentWorldPlaneGeometryData defined above. DataNode::Pointer m_CurrentWorldPlaneGeometryNode; //##Documentation //## @brief test only unsigned long m_CurrentWorldPlaneGeometryTransformTime; std::string m_Name; double m_Bounds[6]; bool m_EmptyWorldGeometry; typedef std::set LODEnabledMappersType; /** Number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int m_NumberOfVisibleLODEnabledMappers; // Local Storage Handling for mappers protected: std::list m_RegisteredLocalStorageHandlers; bool m_ConstrainZoomingAndPanning; public: void RemoveAllLocalStorages(); void RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); void UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); }; } // namespace mitk #endif /* BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 */ diff --git a/Modules/Core/include/mitkDisplayActionEventBroadcast.h b/Modules/Core/include/mitkDisplayActionEventBroadcast.h index 5b197910ef..2de13c1558 100644 --- a/Modules/Core/include/mitkDisplayActionEventBroadcast.h +++ b/Modules/Core/include/mitkDisplayActionEventBroadcast.h @@ -1,224 +1,228 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKDISPLAYACTIONEVENTBROADCAST_H #define MITKDISPLAYACTIONEVENTBROADCAST_H #include "mitkInteractionEventObserver.h" #include namespace mitk { /** * @brief This class serves as an event state machine while simultaneously observing interaction events. * It connects the actions from the event state machine .xml-file with concrete functions of this class. * * The observed interaction events are mouse events that trigger certain actions, according to an event configuration (e.g. PACS mode). * These actions are defined and connected inside this broadcast class. * They typically contain some preprocessing steps and use the results of the preprocessing to broadcast a specific display event. * * Any instance that wants to react on the invoked events can call 'AddObserver' on a specific broadcast instance, * given an itkEventObject and an itkCommand. */ class MITKCORE_EXPORT DisplayActionEventBroadcast : public EventStateMachine, public InteractionEventObserver { public: mitkClassMacro(DisplayActionEventBroadcast, EventStateMachine) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** * By this function this observer is notified about about every 'InteractionEvent'. * The interaction event is passed to the state machine in order to use its infrastructure. * For more information see @see InteractionEventObserver. * * @par interactionEvent The event that was observed and triggered this notification. * @par isHandled Flag that indicates if a 'DataInteractor' has already handled the event. */ void Notify(InteractionEvent* interactionEvent, bool isHandled) override; protected: DisplayActionEventBroadcast(); ~DisplayActionEventBroadcast() override; /** * @brief Connects the action names used in the state machine pattern with functions implemented within this InteractionEventObserver. */ void ConnectActionsAndFunctions() override; /** * @brief This function is executed when a config object is set / changed (via 'SetEventConfig' or 'AddEventConfig' in 'InteractionEventObserver'). * It is used to read out the parameters set in the configuration file and to set the member variables accordingly. */ void ConfigurationChanged() override; /** * @brief Filters the event resp. the sender of the event. * * @par interactionEvent The event whose sender has to be checked * @par data node The data node is ignored in this specific implementation. * * @return True, if the sender of the event is a valid sender and the sending renderer is a 2D-renderer. False, if not. */ bool FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode) override; ////////////////////////////////////////////////////////////////////////// // Functions to react to interaction events (actions) ////////////////////////////////////////////////////////////////////////// /** * @brief Check if the given interaction event is actually an 'InteractionPositionEvent'. * * @par interactionEvent The interaction event that is checked. * * @return True, if the given event can be dynamically cast to an 'InteractionPositionEvent'. False, if not. */ bool CheckPositionEvent(const InteractionEvent* interactionEvent); bool CheckRotationPossible(const InteractionEvent* interactionEvent); bool CheckSwivelPossible(const InteractionEvent* interactionEvent); void Init(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Move(StateMachineAction* stateMachineAction , InteractionEvent* interactionEvent); void SetCrosshair(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Zoom(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Scroll(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void ScrollOneUp(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void ScrollOneDown(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void AdjustLevelWindow(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void StartRotation(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void EndRotation(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Rotate(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); void Swivel(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + void IncreaseTimeStep(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void DecreaseTimeStep(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + private: void UpdateStatusbar(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); bool GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue); /** * @brief Reference to the service registration of the observer. * This is needed to unregister the observer on unload. */ us::ServiceRegistration m_ServiceRegistration; /** * @brief Determines if this broadcast class reacts to events that already have been processed by a DataInteractor. * The default value is false. */ bool m_AlwaysReact; /** * @brief Coordinate of the mouse pointer at beginning of an interaction (translated to mm unit). */ Point2D m_StartCoordinateInMM; /** * @brief Coordinate of the mouse pointer in the last step within an interaction. */ Point2D m_LastDisplayCoordinate; /** * @brief Coordinate of the mouse pointer in the last step within an interaction (translated to mm unit). */ Point2D m_LastCoordinateInMM; /** * \brief Current coordinates of the pointer. */ Point2D m_CurrentDisplayCoordinate; /** * @brief Defines the behavior at the end of a data set. * If set to true, it will restart at end of data set from the beginning. */ bool m_AutoRepeat; /** * @brief Defines how many slices are scrolled per pixel that the mouse pointer was moved. * By default the modifier is 4. This means that when the user moves the cursor by 4 pixels in Y-direction, * the scene is scrolled by one slice. If the user has moved the the cursor by 20 pixels, the scene is * scrolled by 5 slices. * * If the cursor has moved less than m_IndexToSliceModifier pixels, the scene is scrolled by one slice. */ int m_IndexToSliceModifier; /** * @brief Defines the scroll behavior. * Default is up/down movement of pointer performs scrolling */ std::string m_ScrollDirection; /** * @brief Defines how the axis of interaction influences scroll behavior. */ bool m_InvertScrollDirection; /** * @brief Defines the zoom behavior. * Default is up/down movement of pointer performs zooming */ std::string m_ZoomDirection; /** * @brief Defines how the axis of interaction influences zoom behavior. */ bool m_InvertZoomDirection; /** * @brief Factor to adjust zooming speed. */ float m_ZoomFactor; /** * @brief Defines how the axis of interaction influences move behavior. */ bool m_InvertMoveDirection; /** * @brief Defines the level-window behavior. * Default is left/right movement of pointer modifies the level. */ std::string m_LevelDirection; /** * @brief Defines how the axis of interaction influences level-window behavior. */ bool m_InvertLevelWindowDirection; /** * @brief Determines if the angle between crosshair remains fixed when rotating. */ bool m_LinkPlanes; typedef std::vector SNCVector; SNCVector m_RotatableSNCs; SNCVector m_SNCsToBeRotated; Point3D m_LastCursorPosition; Point3D m_CenterOfRotation; Point2D m_ReferenceCursor; Vector3D m_RotationPlaneNormal; Vector3D m_RotationPlaneXVector; Vector3D m_RotationPlaneYVector; Vector3D m_PreviousRotationAxis; ScalarType m_PreviousRotationAngle; }; } // end namespace #endif // MITKDISPLAYACTIONEVENTBROADCAST_H diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp index 925f7bf984..948f7d26e1 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp @@ -1,787 +1,918 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayActionEventBroadcast.h" // us #include "usGetModuleContext.h" #include "usModuleContext.h" // mitk core module -#include "mitkCompositePixelValueToString.h" -#include "mitkDisplayActionEvents.h" -#include "mitkImage.h" -#include "mitkImagePixelReadAccessor.h" -#include "mitkInteractionPositionEvent.h" -#include "mitkLine.h" -#include "mitkNodePredicateDataType.h" -#include "mitkPixelTypeMultiplex.h" -#include "mitkStatusBar.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include mitk::DisplayActionEventBroadcast::DisplayActionEventBroadcast() : m_AlwaysReact(false) , m_AutoRepeat(false) , m_IndexToSliceModifier(4) , m_InvertScrollDirection(false) , m_InvertZoomDirection(false) , m_ZoomFactor(2) , m_InvertMoveDirection(false) , m_InvertLevelWindowDirection(false) , m_LinkPlanes(true) { m_StartCoordinateInMM.Fill(0); m_LastDisplayCoordinate.Fill(0); m_LastCoordinateInMM.Fill(0); m_CurrentDisplayCoordinate.Fill(0); // register the broadcast class (itself) as an interaction event observer via micro services us::ServiceProperties props; props["name"] = std::string("DisplayActionEventBroadcast"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); } mitk::DisplayActionEventBroadcast::~DisplayActionEventBroadcast() { m_ServiceRegistration.Unregister(); } void mitk::DisplayActionEventBroadcast::Notify(InteractionEvent* interactionEvent, bool isHandled) { // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { HandleEvent(interactionEvent, nullptr); } } void mitk::DisplayActionEventBroadcast::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); + + CONNECT_FUNCTION("IncreaseTimeStep", IncreaseTimeStep); + CONNECT_FUNCTION("DecreaseTimeStep", DecreaseTimeStep); } void mitk::DisplayActionEventBroadcast::ConfigurationChanged() { PropertyList::Pointer properties = GetAttributes(); // allwaysReact std::string strAlwaysReact = ""; m_AlwaysReact = false; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } } // auto repeat std::string strAutoRepeat = ""; m_AutoRepeat = false; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; m_IndexToSliceModifier = 4; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; m_LinkPlanes = false; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") { m_LinkPlanes = true; } } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } } bool mitk::DisplayActionEventBroadcast::FilterEvents(InteractionEvent* interactionEvent, DataNode * /*dataNode*/) { BaseRenderer* sendingRenderer = interactionEvent->GetSender(); if (nullptr == sendingRenderer) { return false; } if (BaseRenderer::Standard3D == sendingRenderer->GetMapperID()) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckRotationPossible(const InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - - if there is NO interesection, ignore and continue + - if there is NO intersection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } - BaseRenderer* clickedRenderer = positionEvent->GetSender(); - const PlaneGeometry* ourViewportGeometry = clickedRenderer->GetCurrentWorldPlaneGeometry(); + BaseRenderer* renderer = positionEvent->GetSender(); + if (nullptr == renderer) + { + return false; + } - if (nullptr == ourViewportGeometry) + const PlaneGeometry* rendererWorldPlaneGeometry = renderer->GetCurrentWorldPlaneGeometry(); + if (nullptr == rendererWorldPlaneGeometry) { return false; } - Point3D cursorPosition = positionEvent->GetPositionInWorld(); - const auto spacing = ourViewportGeometry->GetSpacing(); + Point3D position = positionEvent->GetPositionInWorld(); + const auto spacing = rendererWorldPlaneGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); - const double threshholdDistancePixels = 12.0; - - auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); + const ScalarType threshholdDistancePixels = 12.0; - for (auto renWin : renWindows) + auto allRenderWindows = renderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) { - SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); + SliceNavigationController* snc = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. - if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) + if (BaseRenderer::Standard3D == BaseRenderer::GetInstance(renderWindow)->GetMapperID()) + { continue; + } - const PlaneGeometry *otherRenderersRenderPlane = snc->GetCurrentPlaneGeometry(); - if (nullptr == otherRenderersRenderPlane) + const PlaneGeometry* rendererPlaneGeometry = snc->GetCurrentPlaneGeometry(); + if (nullptr == rendererPlaneGeometry) { continue; // ignore, we don't see a plane } - // check if there is an intersection - Line3D intersectionLine; // between rendered/clicked geometry and the one being analyzed - if (!ourViewportGeometry->IntersectionLine(otherRenderersRenderPlane, intersectionLine)) + // check if there is an intersection between rendered / clicked geometry and the one being analyzed + Line3D intersectionLine; + if (!rendererWorldPlaneGeometry->IntersectionLine(rendererPlaneGeometry, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line - const double distanceFromIntersectionLine = intersectionLine.Distance(cursorPosition) / spacing[snc->GetDefaultViewDirection()]; + const double distanceFromIntersectionLine = intersectionLine.Distance(position) / spacing[snc->GetDefaultViewDirection()]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { - anyOtherGeometry = otherRenderersRenderPlane; // we just take the last one, so overwrite each iteration (we just - // need some crossing point) - // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used + // we just take the last one, so overwrite each iteration (we just need some crossing point) + // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used + anyOtherGeometry = rendererPlaneGeometry; if (m_LinkPlanes) { + // if planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (nullptr == geometryToBeRotated) // first one close to the cursor { - geometryToBeRotated = otherRenderersRenderPlane; + geometryToBeRotated = rendererPlaneGeometry; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate - if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && - intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < eps) + if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) + && intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); - if (geometryToBeRotated && anyOtherGeometry && ourViewportGeometry && !hitMultipleLines) + if (geometryToBeRotated && anyOtherGeometry && rendererWorldPlaneGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { - // we DO have enough information for rotation + // we have enough information for rotation // remember where the last cursor position ON THE LINE has been observed - m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project(cursorPosition); + m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project(position); // find center of rotation by intersection with any of the OTHER lines if (anyOtherGeometry->IntersectionPoint(intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) { return true; } else { return false; } } return false; } bool mitk::DisplayActionEventBroadcast::CheckSwivelPossible(const InteractionEvent *interactionEvent) { - const ScalarType ThresholdDistancePixels = 6.0; - // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } - BaseRenderer *renderer = interactionEvent->GetSender(); + BaseRenderer* renderer = positionEvent->GetSender(); if (nullptr == renderer) { return false; } - const Point3D& cursor = positionEvent->GetPositionInWorld(); + const Point3D& position = positionEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry* clickedGeometry(nullptr); const PlaneGeometry* otherGeometry1(nullptr); const PlaneGeometry* otherGeometry2(nullptr); - auto registeredRenderWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); - for (auto renWin : registeredRenderWindows) + const ScalarType threshholdDistancePixels = 6.0; + + auto allRenderWindows = renderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) { - SliceNavigationController* snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); + SliceNavigationController* snc = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. - if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) + if (BaseRenderer::Standard3D == BaseRenderer::GetInstance(renderWindow)->GetMapperID()) + { continue; + } - // unsigned int slice = (*iter)->GetSlice()->GetPos(); - // unsigned int time = (*iter)->GetTime()->GetPos(); - - const PlaneGeometry *planeGeometry = snc->GetCurrentPlaneGeometry(); - if (!planeGeometry) - continue; + const PlaneGeometry* rendererPlaneGeometry = snc->GetCurrentPlaneGeometry(); + if (nullptr == rendererPlaneGeometry) + { + continue; // ignore, we don't see a plane + } if (snc == renderer->GetSliceNavigationController()) { - clickedGeometry = planeGeometry; + clickedGeometry = rendererPlaneGeometry; m_SNCsToBeRotated.push_back(snc); } else { - if (otherGeometry1 == nullptr) + if (nullptr == otherGeometry1) { - otherGeometry1 = planeGeometry; + otherGeometry1 = rendererPlaneGeometry; } else { - otherGeometry2 = planeGeometry; + otherGeometry2 = rendererPlaneGeometry; } if (m_LinkPlanes) { - // If planes are linked, apply rotation to all planes + // if planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } Line3D line; Point3D point; - if ((clickedGeometry != nullptr) && (otherGeometry1 != nullptr) && (otherGeometry2 != nullptr) && - clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) + if ((nullptr != clickedGeometry) && (nullptr != otherGeometry1) && (nullptr != otherGeometry2) + && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; - if (m_CenterOfRotation.EuclideanDistanceTo(cursor) < ThresholdDistancePixels) + if (m_CenterOfRotation.EuclideanDistanceTo(position) < threshholdDistancePixels) { return false; } else { m_ReferenceCursor = positionEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = { 1.0, 0.0, 0.0 }; ScalarType yVector[] = { 0.0, 1.0, 0.0 }; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayActionEventBroadcast::Init(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); m_LastCoordinateInMM = m_StartCoordinateInMM; } void mitk::DisplayActionEventBroadcast::Move(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } BaseRenderer* sender = interactionEvent->GetSender(); Vector2D moveVector = m_LastDisplayCoordinate - positionEvent->GetPointerPositionOnScreen(); if (m_InvertMoveDirection) { moveVector *= -1.0; } moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); // #TODO: put here? // store new display coordinate m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate move event with computed geometry values InvokeEvent(DisplayMoveEvent(interactionEvent, moveVector)); } void mitk::DisplayActionEventBroadcast::SetCrosshair(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } Point3D position = positionEvent->GetPositionInWorld(); // propagate set crosshair event with computed geometry values InvokeEvent(DisplaySetCrosshairEvent(interactionEvent, position)); } void mitk::DisplayActionEventBroadcast::Zoom(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate zoom event with computed geometry values InvokeEvent(DisplayZoomEvent(interactionEvent, factor, m_StartCoordinateInMM)); } void mitk::DisplayActionEventBroadcast::Scroll(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } int sliceDelta = 0; // scroll direction if (m_ScrollDirection == "updown") { sliceDelta = static_cast(m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]); } else { sliceDelta = static_cast(m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]); } if (m_InvertScrollDirection) { sliceDelta *= -1; } // set how many pixels the mouse has to be moved to scroll one slice // if the mouse has been moved less than 'm_IndexToSliceModifier', pixels slice ONE slice only if (sliceDelta > 0 && sliceDelta < m_IndexToSliceModifier) { sliceDelta = m_IndexToSliceModifier; } else if (sliceDelta < 0 && sliceDelta > -m_IndexToSliceModifier) { sliceDelta = -m_IndexToSliceModifier; } sliceDelta /= m_IndexToSliceModifier; // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate scroll event with computed geometry values InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::ScrollOneUp(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = 1; if (m_InvertScrollDirection) { sliceDelta = -1; } // propagate scroll event with a single slice delta (increase) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::ScrollOneDown(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = -1; if (m_InvertScrollDirection) { sliceDelta = 1; } // propagate scroll event with a single slice delta (decrease) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::AdjustLevelWindow(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } ScalarType level; ScalarType window; if (m_LevelDirection == "leftright") { level = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; window = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { level = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; window = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertLevelWindowDirection) { level *= -1; window *= -1; } level *= static_cast(2); window *= static_cast(2); // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate set level window event with the level and window delta InvokeEvent(DisplaySetLevelWindowEvent(interactionEvent, level, window)); } void mitk::DisplayActionEventBroadcast::StartRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { - // nothing here; no event sent + SetMouseCursor(rotate_cursor_xpm, 0, 0); } void mitk::DisplayActionEventBroadcast::EndRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { - // nothing here; no event sent + ResetMouseCursor(); } -void mitk::DisplayActionEventBroadcast::Rotate(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) +void mitk::DisplayActionEventBroadcast::Rotate(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { - // nothing here; no event sent + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + Point3D position = positionEvent->GetPositionInWorld(); + + Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; + Vector3D toCursor = position - m_CenterOfRotation; + + // cross product: | A x B | = |A| * |B| * sin(angle) + Vector3D axisOfRotation; + vnl_vector_fixed vnlDirection = vnl_cross_3d(toCursor.GetVnlVector(), toProjected.GetVnlVector()); + axisOfRotation.SetVnlVector(vnlDirection); + + // scalar product: A * B = |A| * |B| * cos(angle) + // tan = sin / cos + ScalarType angle = -atan2((double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected)); + angle *= 180.0 / vnl_math::pi; + m_LastCursorPosition = position; + + // create RotationOperation and apply to all SNCs that should be rotated + RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); + + // iterate the OTHER slice navigation controllers + for (auto iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) + { + TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry(); + if (nullptr == timeGeometry) + { + continue; + } + + timeGeometry->ExecuteOperation(&rotationOperation); + + (*iter)->SendCreatedWorldGeometryUpdate(); + } + + RenderingManager::GetInstance()->RequestUpdateAll(); } -void mitk::DisplayActionEventBroadcast::Swivel(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) +void mitk::DisplayActionEventBroadcast::Swivel(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { - // nothing here; no event sent + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + // Determine relative mouse movement projected onto world space + Point2D position = positionEvent->GetPointerPositionOnScreen(); + + Vector2D relativeCursor = position - m_ReferenceCursor; + Vector3D relativeCursorAxis = m_RotationPlaneXVector * relativeCursor[0] + m_RotationPlaneYVector * relativeCursor[1]; + + // Determine rotation axis (perpendicular to rotation plane and cursor movement) + Vector3D rotationAxis = itk::CrossProduct(m_RotationPlaneNormal, relativeCursorAxis); + + ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0; + + // Restore the initial plane pose by undoing the previous rotation operation + RotationOperation op(OpROTATE, m_CenterOfRotation, m_PreviousRotationAxis, -m_PreviousRotationAngle); + + SNCVector::iterator iter; + for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) + { + if (!(*iter)->GetSliceRotationLocked()) + { + TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry(); + if (nullptr == timeGeometry) + { + continue; + } + + timeGeometry->ExecuteOperation(&op); + (*iter)->SendCreatedWorldGeometryUpdate(); + } + } + + // Apply new rotation operation to all relevant SNCs + RotationOperation op2(OpROTATE, m_CenterOfRotation, rotationAxis, rotationAngle); + + for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) + { + if (!(*iter)->GetSliceRotationLocked()) + { + // Retrieve the TimeGeometry of this SliceNavigationController + TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); + if (nullptr == timeGeometry) + { + continue; + } + + // Execute the new rotation + timeGeometry->ExecuteOperation(&op2); + + // Notify listeners + (*iter)->SendCreatedWorldGeometryUpdate(); + } + } + + m_PreviousRotationAxis = rotationAxis; + m_PreviousRotationAngle = rotationAngle; + + RenderingManager::GetInstance()->RequestUpdateAll(); + return; +} + +void mitk::DisplayActionEventBroadcast::IncreaseTimeStep(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); + auto stepper = sliceNaviController->GetTime(); + stepper->SetAutoRepeat(true); + stepper->Next(); +} + +void mitk::DisplayActionEventBroadcast::DecreaseTimeStep(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); + auto stepper = sliceNaviController->GetTime(); + stepper->SetAutoRepeat(true); + stepper->Previous(); } void mitk::DisplayActionEventBroadcast::UpdateStatusbar(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } BaseRenderer::Pointer renderer = positionEvent->GetSender(); TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); DataStorage::SetOfObjects::ConstPointer nodes = renderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); if (nodes.IsNull()) { return; } Point3D worldposition; renderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); auto globalCurrentTimePoint = renderer->GetTime(); Image::Pointer image3D; DataNode::Pointer node; DataNode::Pointer topSourceNode; int component = 0; node = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, renderer); if (node.IsNull()) { return; } bool isBinary(false); node->GetBoolProperty("binary", isBinary); if (isBinary) { DataStorage::SetOfObjects::ConstPointer sourcenodes = renderer->GetDataStorage()->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { topSourceNode = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, renderer); } if (topSourceNode.IsNotNull()) { image3D = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } // get the position and pixel value from the image and build up status bar text auto statusBar = StatusBar::GetInstance(); if (image3D.IsNotNull() && statusBar != nullptr) { itk::Index<3> p; image3D->GetGeometry()->WorldToIndex(worldposition, p); auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) { std::string pixelValue = "Pixel RGB(A) value: "; pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); } else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) { std::string pixelValue = "See ODF Details view. "; statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); } else { ScalarType pixelValue; mitkPixelTypeMultiplex5( FastSinglePixelAccess, image3D->GetChannelDescriptor().GetPixelType(), image3D, image3D->GetVolumeData(renderer->GetTimeStep()), p, pixelValue, component); statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue); } } else { statusBar->DisplayImageInfoInvalid(); } } bool mitk::DisplayActionEventBroadcast::GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp b/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp index bf8a7f9abe..5936b5fa48 100644 --- a/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp @@ -1,951 +1,951 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayInteractor.h" #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkInteractionPositionEvent.h" #include "mitkPropertyList.h" #include #include #include // level window #include "mitkLevelWindow.h" #include "mitkLevelWindowProperty.h" #include "mitkLine.h" #include "mitkNodePredicateDataType.h" #include "mitkStandaloneDataStorage.h" #include "vtkRenderWindowInteractor.h" // Rotation #include "mitkInteractionConst.h" #include "rotate_cursor.xpm" #include #include #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include "mitkStatusBar.h" #include void mitk::DisplayInteractor::Notify(InteractionEvent *interactionEvent, bool isHandled) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { HandleEvent(interactionEvent, nullptr); } } mitk::DisplayInteractor::DisplayInteractor() : m_IndexToSliceModifier(4) , m_AutoRepeat(false) , m_InvertScrollDirection(false) , m_InvertZoomDirection(false) , m_InvertMoveDirection(false) , m_InvertLevelWindowDirection(false) , m_AlwaysReact(false) , m_ZoomFactor(2) , m_LinkPlanes(true) { m_StartCoordinateInMM.Fill(0); m_LastDisplayCoordinate.Fill(0); m_LastCoordinateInMM.Fill(0); m_CurrentDisplayCoordinate.Fill(0); } mitk::DisplayInteractor::~DisplayInteractor() { // nothing here } void mitk::DisplayInteractor::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); CONNECT_FUNCTION("IncreaseTimeStep", IncreaseTimeStep); CONNECT_FUNCTION("DecreaseTimeStep", DecreaseTimeStep); } bool mitk::DisplayInteractor::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) { return false; } return true; } bool mitk::DisplayInteractor::CheckRotationPossible(const mitk::InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - if there is NO interesection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto *posEvent = dynamic_cast(interactionEvent); if (posEvent == nullptr) return false; BaseRenderer *clickedRenderer = posEvent->GetSender(); const PlaneGeometry *ourViewportGeometry = (clickedRenderer->GetCurrentWorldPlaneGeometry()); if (!ourViewportGeometry) return false; Point3D cursorPosition = posEvent->GetPositionInWorld(); const auto spacing = ourViewportGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); const double threshholdDistancePixels = 12.0; auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; const PlaneGeometry *otherRenderersRenderPlane = snc->GetCurrentPlaneGeometry(); if (otherRenderersRenderPlane == nullptr) continue; // ignore, we don't see a plane // check if there is an intersection Line3D intersectionLine; // between rendered/clicked geometry and the one being analyzed if (!ourViewportGeometry->IntersectionLine(otherRenderersRenderPlane, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line const double distanceFromIntersectionLine = intersectionLine.Distance(cursorPosition) / spacing[snc->GetDefaultViewDirection()]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { anyOtherGeometry = otherRenderersRenderPlane; // we just take the last one, so overwrite each iteration (we just // need some crossing point) // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used if (m_LinkPlanes) { m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (geometryToBeRotated == nullptr) // first one close to the cursor { geometryToBeRotated = otherRenderersRenderPlane; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < mitk::eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); if (geometryToBeRotated && anyOtherGeometry && ourViewportGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { // we DO have enough information for rotation m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project( cursorPosition); // remember where the last cursor position ON THE LINE has been observed if (anyOtherGeometry->IntersectionPoint( intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) // find center of rotation by intersection with any of the OTHER lines { return true; } else { return false; } } return false; } bool mitk::DisplayInteractor::CheckSwivelPossible(const mitk::InteractionEvent *interactionEvent) { const ScalarType ThresholdDistancePixels = 6.0; // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto *posEvent = dynamic_cast(interactionEvent); BaseRenderer *renderer = interactionEvent->GetSender(); if (!posEvent || !renderer) return false; const Point3D &cursor = posEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry *clickedGeometry(nullptr); const PlaneGeometry *otherGeometry1(nullptr); const PlaneGeometry *otherGeometry2(nullptr); auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; // unsigned int slice = (*iter)->GetSlice()->GetPos(); // unsigned int time = (*iter)->GetTime()->GetPos(); const PlaneGeometry *planeGeometry = snc->GetCurrentPlaneGeometry(); if (!planeGeometry) continue; if (snc == renderer->GetSliceNavigationController()) { clickedGeometry = planeGeometry; m_SNCsToBeRotated.push_back(snc); } else { if (otherGeometry1 == nullptr) { otherGeometry1 = planeGeometry; } else { otherGeometry2 = planeGeometry; } if (m_LinkPlanes) { // If planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } mitk::Line3D line; mitk::Point3D point; if ((clickedGeometry != nullptr) && (otherGeometry1 != nullptr) && (otherGeometry2 != nullptr) && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; if (m_CenterOfRotation.EuclideanDistanceTo(cursor) < ThresholdDistancePixels) { return false; } else { m_ReferenceCursor = posEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = {1.0, 0.0, 0.0}; ScalarType yVector[] = {0.0, 1.0, 0.0}; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayInteractor::Init(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); m_LastCoordinateInMM = m_StartCoordinateInMM; } void mitk::DisplayInteractor::Move(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer *sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); float invertModifier = -1.0; if (m_InvertMoveDirection) { invertModifier = 1.0; } // perform translation Vector2D moveVector = (positionEvent->GetPointerPositionOnScreen() - m_LastDisplayCoordinate) * invertModifier; moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); sender->GetCameraController()->MoveBy(moveVector); sender->GetRenderingManager()->RequestUpdate(sender->GetRenderWindow()); m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); } void mitk::DisplayInteractor::SetCrosshair(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { auto* positionEvent = static_cast(interactionEvent); Point3D pos = positionEvent->GetPositionInWorld(); const BaseRenderer::Pointer sender = interactionEvent->GetSender(); auto renWindows = sender->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard2D && renWin != sender->GetRenderWindow()) { BaseRenderer::GetInstance(renWin)->GetSliceNavigationController()->SelectSliceByPoint(pos); } } } void mitk::DisplayInteractor::IncreaseTimeStep(StateMachineAction *, InteractionEvent *interactionEvent) { auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Next(); } void mitk::DisplayInteractor::DecreaseTimeStep(StateMachineAction *, InteractionEvent *interactionEvent) { auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Previous(); } void mitk::DisplayInteractor::Zoom(StateMachineAction *, InteractionEvent *interactionEvent) { float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } auto* positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); if (factor != 1.0) { const BaseRenderer::Pointer sender = interactionEvent->GetSender(); sender->GetCameraController()->Zoom(factor, m_StartCoordinateInMM); sender->GetRenderingManager()->RequestUpdate(sender->GetRenderWindow()); } } void mitk::DisplayInteractor::Scroll(StateMachineAction *, InteractionEvent *interactionEvent) { auto* positionEvent = static_cast(interactionEvent); mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (sliceNaviController) { int delta = 0; // Scrolling direction if (m_ScrollDirection == "updown") { delta = static_cast(m_LastDisplayCoordinate[1] - positionEvent->GetPointerPositionOnScreen()[1]); } else { delta = static_cast(m_LastDisplayCoordinate[0] - positionEvent->GetPointerPositionOnScreen()[0]); } if (m_InvertScrollDirection) { delta *= -1; } // Set how many pixels the mouse has to be moved to scroll one slice // if we moved less than 'm_IndexToSliceModifier' pixels slice ONE slice only if (delta > 0 && delta < m_IndexToSliceModifier) { delta = m_IndexToSliceModifier; } else if (delta < 0 && delta > -m_IndexToSliceModifier) { delta = -m_IndexToSliceModifier; } delta /= m_IndexToSliceModifier; int newPos = sliceNaviController->GetSlice()->GetPos() + delta; // if auto repeat is on, start at first slice if you reach the last slice and vice versa int maxSlices = sliceNaviController->GetSlice()->GetSteps(); if (m_AutoRepeat) { while (newPos < 0) { newPos += maxSlices; } while (newPos >= maxSlices) { newPos -= maxSlices; } } else { // if the new slice is below 0 we still show slice 0 // due to the stepper using unsigned int we have to do this ourselves if (newPos < 1) { newPos = 0; } } m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // set the new position sliceNaviController->GetSlice()->SetPos(newPos); } } void mitk::DisplayInteractor::ScrollOneDown(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (!sliceNaviController->GetSliceLocked()) { mitk::Stepper *stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } stepper->Next(); } } void mitk::DisplayInteractor::ScrollOneUp(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (!sliceNaviController->GetSliceLocked()) { mitk::Stepper *stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } stepper->Previous(); } } void mitk::DisplayInteractor::AdjustLevelWindow(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer::Pointer sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // search for active image mitk::DataStorage::Pointer storage = sender->GetDataStorage(); mitk::DataNode::Pointer node = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(mitk::NodePredicateDataType::New("Image")); for (unsigned int i = 0; i < allImageNodes->size(); ++i) { bool isActiveImage = false; bool propFound = allImageNodes->at(i)->GetBoolProperty("imageForLevelWindow", isActiveImage); if (propFound && isActiveImage) { node = allImageNodes->at(i); continue; } } if (node.IsNull()) { node = storage->GetNode(mitk::NodePredicateDataType::New("Image")); } if (node.IsNull()) { return; } mitk::LevelWindow lv = mitk::LevelWindow(); node->GetLevelWindow(lv); ScalarType level = lv.GetLevel(); ScalarType window = lv.GetWindow(); int levelIndex = 0; int windowIndex = 1; if (m_LevelDirection != "leftright") { levelIndex = 1; windowIndex = 0; } int directionModifier = 1; if (m_InvertLevelWindowDirection) { directionModifier = -1; } // calculate adjustments from mouse movements level += (m_CurrentDisplayCoordinate[levelIndex] - m_LastDisplayCoordinate[levelIndex]) * static_cast(2) * directionModifier; window += (m_CurrentDisplayCoordinate[windowIndex] - m_LastDisplayCoordinate[windowIndex]) * static_cast(2) * directionModifier; lv.SetLevelWindow(level, window); dynamic_cast(node->GetProperty("levelwindow"))->SetLevelWindow(lv); sender->GetRenderingManager()->RequestUpdateAll(); } void mitk::DisplayInteractor::StartRotation(mitk::StateMachineAction *, mitk::InteractionEvent *) { this->SetMouseCursor(rotate_cursor_xpm, 0, 0); } void mitk::DisplayInteractor::EndRotation(mitk::StateMachineAction *, mitk::InteractionEvent *) { this->ResetMouseCursor(); } void mitk::DisplayInteractor::Rotate(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto *posEvent = dynamic_cast(event); if (posEvent == nullptr) return; Point3D cursor = posEvent->GetPositionInWorld(); Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; Vector3D toCursor = cursor - m_CenterOfRotation; // cross product: | A x B | = |A| * |B| * sin(angle) Vector3D axisOfRotation; vnl_vector_fixed vnlDirection = vnl_cross_3d(toCursor.GetVnlVector(), toProjected.GetVnlVector()); axisOfRotation.SetVnlVector(vnlDirection); // scalar product: A * B = |A| * |B| * cos(angle) // tan = sin / cos ScalarType angle = -atan2((double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected)); angle *= 180.0 / vnl_math::pi; m_LastCursorPosition = cursor; // create RotationOperation and apply to all SNCs that should be rotated RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); // iterate the OTHER slice navigation controllers: these are filled in DoDecideBetweenRotationAndSliceSelection for (auto iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; timeGeometry->ExecuteOperation(&rotationOperation); (*iter)->SendCreatedWorldGeometryUpdate(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::DisplayInteractor::Swivel(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto *posEvent = dynamic_cast(event); if (!posEvent) return; // Determine relative mouse movement projected onto world space Point2D cursor = posEvent->GetPointerPositionOnScreen(); Vector2D relativeCursor = cursor - m_ReferenceCursor; Vector3D relativeCursorAxis = m_RotationPlaneXVector * relativeCursor[0] + m_RotationPlaneYVector * relativeCursor[1]; // Determine rotation axis (perpendicular to rotation plane and cursor // movement) Vector3D rotationAxis = itk::CrossProduct(m_RotationPlaneNormal, relativeCursorAxis); ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0; // Restore the initial plane pose by undoing the previous rotation // operation RotationOperation op(OpROTATE, m_CenterOfRotation, m_PreviousRotationAxis, -m_PreviousRotationAngle); SNCVector::iterator iter; for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; timeGeometry->ExecuteOperation(&op); (*iter)->SendCreatedWorldGeometryUpdate(); } } // Apply new rotation operation to all relevant SNCs RotationOperation op2(OpROTATE, m_CenterOfRotation, rotationAxis, rotationAngle); for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { // Retrieve the TimeGeometry of this SliceNavigationController TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; // Execute the new rotation timeGeometry->ExecuteOperation(&op2); // Notify listeners (*iter)->SendCreatedWorldGeometryUpdate(); } } m_PreviousRotationAxis = rotationAxis; m_PreviousRotationAngle = rotationAngle; RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::DisplayInteractor::UpdateStatusbar(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto* posEvent = dynamic_cast(event); if (nullptr == posEvent) { return; } const mitk::BaseRenderer::Pointer baseRenderer = posEvent->GetSender(); TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); auto globalCurrentTimePoint = baseRenderer->GetTime(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = baseRenderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); if (nodes.IsNull()) { return; } // posEvent->GetPositionInWorld() would return the world position at the // time of initiating the interaction. However, we need to update the // status bar with the position after changing slice. Therefore, we // translate the same display position with the renderer again to // get the new world position. Point3D worldposition; baseRenderer->DisplayToWorld(posEvent->GetPointerPositionOnScreen(), worldposition); mitk::Image::Pointer image3D; mitk::DataNode::Pointer node; mitk::DataNode::Pointer topSourceNode; int component = 0; node = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, baseRenderer); if (node.IsNull()) { return; } bool isBinary(false); node->GetBoolProperty("binary", isBinary); if (isBinary) { mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = baseRenderer->GetDataStorage()->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { - topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, worldposition, globalCurrentTimePoint, baseRenderer); - } - if (topSourceNode.IsNotNull()) - { - image3D = dynamic_cast(topSourceNode->GetData()); - topSourceNode->GetIntProperty("Image.Displayed Component", component); - } - else - { - image3D = dynamic_cast(node->GetData()); - node->GetIntProperty("Image.Displayed Component", component); - } - } - else - { - image3D = dynamic_cast(node->GetData()); - node->GetIntProperty("Image.Displayed Component", component); - } + topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, worldposition, globalCurrentTimePoint, baseRenderer); + } + if (topSourceNode.IsNotNull()) + { + image3D = dynamic_cast(topSourceNode->GetData()); + topSourceNode->GetIntProperty("Image.Displayed Component", component); + } + else + { + image3D = dynamic_cast(node->GetData()); + node->GetIntProperty("Image.Displayed Component", component); + } + } + else + { + image3D = dynamic_cast(node->GetData()); + node->GetIntProperty("Image.Displayed Component", component); + } // get the position and gray value from the image and build up status bar text auto statusBar = StatusBar::GetInstance(); if (image3D.IsNotNull() && statusBar != nullptr) { itk::Index<3> p; image3D->GetGeometry()->WorldToIndex(worldposition, p); auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) { std::string pixelValue = "Pixel RGB(A) value: "; pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue.c_str()); } else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) { std::string pixelValue = "See ODF Details view. "; statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue.c_str()); } else { mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image3D->GetChannelDescriptor().GetPixelType(), image3D, image3D->GetVolumeData(image3D->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), p, pixelValue, component); statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue); } } else { statusBar->DisplayImageInfoInvalid(); } } void mitk::DisplayInteractor::ConfigurationChanged() { mitk::PropertyList::Pointer properties = GetAttributes(); // auto repeat std::string strAutoRepeat = ""; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } else { m_AutoRepeat = false; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } else { m_IndexToSliceModifier = 4; } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") m_LinkPlanes = true; else m_LinkPlanes = false; } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } // allwaysReact std::string strAlwaysReact = ""; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } else { m_AlwaysReact = false; } } else { m_AlwaysReact = false; } } bool mitk::DisplayInteractor::FilterEvents(InteractionEvent *interactionEvent, DataNode * /*dataNode*/) { if (interactionEvent->GetSender() == nullptr) return false; if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard3D) return false; return true; } bool mitk::DisplayInteractor::GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char *propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index ec5e57aa47..db1772bbdd 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,124 +1,128 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES QmitkAbstractDataStorageModel.cpp + QmitkAbstractMultiWidget.cpp QmitkApplicationCursor.cpp QmitkDataStorageComboBox.cpp QmitkDataStorageDefaultListModel.cpp QmitkDataStorageListModel.cpp QmitkDataStorageTableModel.cpp QmitkDataStorageSimpleTreeModel.cpp QmitkDataStorageTreeModel.cpp QmitkDataStorageTreeModelInternalItem.cpp QmitkDnDDataNodeWidget.cpp QmitkFileReaderOptionsDialog.cpp QmitkFileReaderWriterOptionsWidget.cpp QmitkFileWriterOptionsDialog.cpp QmitkInteractionSchemeToolBar.cpp QmitkIOUtil.cpp QmitkLevelWindowPresetDefinitionDialog.cpp QmitkLevelWindowRangeChangeDialog.cpp QmitkLevelWindowWidgetContextMenu.cpp QmitkLevelWindowWidget.cpp QmitkLineEditLevelWindowWidget.cpp QmitkMemoryUsageIndicatorView.cpp QmitkMouseModeSwitcher.cpp QmitkMimeTypes.cpp QmitkMultiWidgetConfigurationToolBar.cpp + QmitkMultiWidgetLayoutManager.cpp QmitkMultiWidgetLayoutSelectionWidget.cpp QmitkNodeDescriptor.cpp QmitkColoredNodeDescriptor.cpp QmitkNodeDescriptorManager.cpp QmitkProgressBar.cpp QmitkPropertiesTableEditor.cpp QmitkPropertiesTableModel.cpp QmitkPropertyDelegate.cpp QmitkRegisterClasses.cpp QmitkRenderingManager.cpp QmitkRenderingManagerFactory.cpp QmitkRenderWindow.cpp QmitkRenderWindowMenu.cpp QmitkRenderWindowWidget.cpp QmitkServiceListWidget.cpp QmitkSliderLevelWindowWidget.cpp QmitkStdMultiWidget.cpp QmitkMxNMultiWidget.cpp QmitkDataStorageComboBoxWithSelectNone.cpp QmitkDataStorageFilterProxyModel.cpp QmitkPropertyItem.cpp QmitkPropertyItemDelegate.cpp QmitkPropertyItemModel.cpp QmitkStyleManager.cpp QmitkAbstractDataStorageInspector.cpp QmitkDataStorageListInspector.cpp QmitkDataStorageTreeInspector.cpp QmitkModelViewSelectionConnector.cpp mitkIDataStorageInspectorProvider.cpp mitkQtWidgetsActivator.cpp mitkDataStorageInspectorGenerator.cpp QmitkOverlayWidget.cpp QmitkNodeDetailsDialog.cpp ) set(MOC_H_FILES include/QmitkAbstractDataStorageModel.h + include/QmitkAbstractMultiWidget.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h include/QmitkDataStorageSimpleTreeModel.h include/QmitkDataStorageDefaultListModel.h include/QmitkDnDDataNodeWidget.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkInteractionSchemeToolBar.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkMouseModeSwitcher.h include/QmitkMultiWidgetConfigurationToolBar.h + include/QmitkMultiWidgetLayoutManager.h include/QmitkMultiWidgetLayoutSelectionWidget.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkRenderWindowMenu.h include/QmitkRenderWindowWidget.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMxNMultiWidget.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h include/QmitkDataStorageListInspector.h include/QmitkAbstractDataStorageInspector.h include/QmitkDataStorageTreeInspector.h include/QmitkModelViewSelectionConnector.h include/QmitkOverlayWidget.h include/QmitkNodeDetailsDialog.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkMultiWidgetLayoutSelectionWidget.ui src/QmitkServiceListWidgetControls.ui src/QmitkDataStorageListInspector.ui src/QmitkDataStorageTreeInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h b/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h new file mode 100644 index 0000000000..fdc454967b --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h @@ -0,0 +1,167 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKABSTRACTMULTIWIDGET_H +#define QMITKABSTRACTMULTIWIDGET_H + +// mitk qt widgets module +#include "MitkQtWidgetsExports.h" + +// mitk core +#include +#include +#include + +// qt +#include + +// c++ +#include +#include + +class QmitkMultiWidgetLayoutManager; +class QmitkRenderWindow; +class QmitkRenderWindowWidget; + +namespace mitk +{ + class DataStorage; + class InteractionEventHandler; + class RenderingManager; +} + +/** +* @brief The 'QmitkAbstractMultiWidget' is a 'QWidget' that can be subclassed to display multiple render windows at once. +* Render windows can dynamically be added and removed to change the layout of the multi widget. +* A subclass of this multi widget can be used inside a 'QmitkAbstractMultiWidgetEditor'. +* +* The class uses the 'DisplayActionEventBroadcast' and 'DisplayActionEventHandler' classes to +* load a state machine and set an event configuration. +* +* Using the 'Synchronize' function the user can enable or disable the synchronization of display action events. +* See 'DisplayActionEventFunctions'-class for the different synchronized and non-synchronized functions used. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractMultiWidget : public QWidget +{ + Q_OBJECT + +public: + + using RenderWindowWidgetPointer = std::shared_ptr; + using RenderWindowWidgetMap = std::map>; + using RenderWindowHash = QHash; + using ViewDirection = mitk::BaseRenderer::ViewDirection; + + QmitkAbstractMultiWidget(QWidget* parent = 0, + Qt::WindowFlags f = 0, + mitk::RenderingManager* renderingManager = nullptr, + mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, + const QString& multiWidgetName = "multiwidget"); + + virtual ~QmitkAbstractMultiWidget(); + + virtual void InitializeMultiWidget() = 0; + virtual void MultiWidgetOpened() { } + virtual void MultiWidgetClosed() { } + + virtual void SetDataStorage(mitk::DataStorage* dataStorage); + mitk::DataStorage* GetDataStorage() const; + + mitk::RenderingManager* GetRenderingManager() const; + + int GetRowCount() const; + int GetColumnCount() const; + virtual void SetLayout(int row, int column); + + virtual void Synchronize(bool synchronized); + virtual void SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); + + mitk::InteractionEventHandler* GetInteractionEventHandler(); + + RenderWindowWidgetMap GetRenderWindowWidgets() const; + RenderWindowWidgetMap Get2DRenderWindowWidgets() const; + RenderWindowWidgetMap Get3DRenderWindowWidgets() const; + RenderWindowWidgetPointer GetRenderWindowWidget(int row, int column) const; + RenderWindowWidgetPointer GetRenderWindowWidget(const QString& widgetName) const; + RenderWindowWidgetPointer GetRenderWindowWidget(const QmitkRenderWindow* renderWindow) const; + RenderWindowHash GetRenderWindows() const; + QmitkRenderWindow* GetRenderWindow(int row, int column) const; + virtual QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const; + virtual QmitkRenderWindow* GetRenderWindow(const ViewDirection& viewDirection) const = 0; + + virtual void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget); + RenderWindowWidgetPointer GetActiveRenderWindowWidget() const; + RenderWindowWidgetPointer GetFirstRenderWindowWidget() const; + RenderWindowWidgetPointer GetLastRenderWindowWidget() const; + + virtual QString GetNameFromIndex(int row, int column) const; + virtual QString GetNameFromIndex(size_t index) const; + + unsigned int GetNumberOfRenderWindowWidgets() const; + + void RequestUpdate(const QString& widgetName); + void RequestUpdateAll(); + void ForceImmediateUpdate(const QString& widgetName); + void ForceImmediateUpdateAll(); + + virtual void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) = 0; + virtual const mitk::Point3D GetSelectedPosition(const QString& widgetName) const = 0; + + virtual void SetCrosshairVisibility(bool visible) = 0; + virtual bool GetCrosshairVisibility() const = 0; + + virtual void ResetCrosshair() = 0; + + virtual void SetWidgetPlaneMode(int mode) = 0; + + virtual void ActivateMenuWidget(bool state); + virtual bool IsMenuWidgetEnabled() const; + + QmitkMultiWidgetLayoutManager* GetMultiWidgetLayoutManager() const; + +Q_SIGNALS: + + void ActiveRenderWindowChanged(); + +protected: + + virtual void AddRenderWindowWidget(const QString& widgetName, RenderWindowWidgetPointer renderWindowWidget); + virtual void RemoveRenderWindowWidget(); + +private: + + /** + * @brief This function will be called by the function 'SetLayout' and + * can be implemented and customized in the subclasses. + */ + virtual void SetLayoutImpl() = 0; + /** + * @brief This function will be called by the function 'Synchronize' and + * can be implemented and customized in the subclasses. + */ + virtual void SynchronizeImpl() = 0; + /** + * @brief This function will be called by the function 'SetInteractionScheme' and + * can be implemented and customized in the subclasses. + */ + virtual void SetInteractionSchemeImpl() = 0; + + struct Impl; + std::unique_ptr m_Impl; + +}; + +#endif // QMITKABSTRACTMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h b/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h index 8cf0379174..e13c26ac1c 100644 --- a/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h +++ b/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h @@ -1,66 +1,70 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H #define QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H #include "MitkQtWidgetsExports.h" #include + +// qt #include -// mitk qtwidgets -#include "QmitkMultiWidgetLayoutSelectionWidget.h" +class QmitkAbstractMultiWidget; +class QmitkMultiWidgetLayoutSelectionWidget; /** * @brief * * */ class MITKQTWIDGETS_EXPORT QmitkMultiWidgetConfigurationToolBar : public QToolBar { Q_OBJECT public: - QmitkMultiWidgetConfigurationToolBar(); + QmitkMultiWidgetConfigurationToolBar(QmitkAbstractMultiWidget* multiWidget); ~QmitkMultiWidgetConfigurationToolBar() override; Q_SIGNALS: void LayoutSet(int row, int column); void Synchronized(bool synchronized); void InteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); protected Q_SLOTS: void OnSetLayout(); void OnSynchronize(); void OnInteractionSchemeChanged(); private: void InitializeToolBar();; void AddButtons(); + QmitkAbstractMultiWidget* m_MultiWidget; + QAction* m_SynchronizeAction; QAction* m_InteractionSchemeChangeAction; QmitkMultiWidgetLayoutSelectionWidget* m_LayoutSelectionPopup; }; #endif // QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H diff --git a/Modules/QtWidgets/include/QmitkMultiWidgetLayoutManager.h b/Modules/QtWidgets/include/QmitkMultiWidgetLayoutManager.h new file mode 100644 index 0000000000..4bcc6db371 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkMultiWidgetLayoutManager.h @@ -0,0 +1,131 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKMULTIWIDGETLAYOUTMANAGER_H +#define QMITKMULTIWIDGETLAYOUTMANAGER_H + +#include "MitkQtWidgetsExports.h" + +#include + +class QmitkAbstractMultiWidget; +class QmitkRenderWindowWidget; + +/** +* @brief The layout manager provides different layout-functions that can modify the layout of an QmitkAbstractMultiWidget. +* +* The constructor is used with the specific multi widget that should be modified. The function 'SetLayoutDesign' +* can then be used to modify the layout of the multi widget. The function needs to be called with the signal-slot +* syntax from a 'QmitkRenderWindow' since it retrieves the specific render window and sets it as the current render window. +* Some layouts work with a specific render window (e.g. ONE_BIG / SetOneBigLayout()), so the current render window is +* then used by these layout functions. +* The publicly accessible layout functions can also be called directly but in order to work the current render window +* needs to be set before by using 'SetCurrentRenderWindowWidget'. +* +*/ +class MITKQTWIDGETS_EXPORT QmitkMultiWidgetLayoutManager : public QObject +{ + Q_OBJECT + +public: + + enum class LayoutDesign + { + DEFAULT = 0, + ALL_2D_TOP_3D_BOTTOM, + ALL_2D_LEFT_3D_RIGHT, + ONE_BIG, + ONLY_2D_HORIZONTAL, + ONLY_2D_VERTICAL, + ONE_TOP_3D_BOTTOM, + ONE_LEFT_3D_RIGHT, + ALL_HORIZONTAL, + ALL_VERTICAL, + REMOVE_ONE, + NONE + }; + + QmitkMultiWidgetLayoutManager(QmitkAbstractMultiWidget* multiwidget); + + /** + * @brief This function is called by render window widgets. Given a specific + * layout design the layout of the multi widget data member is set with this method. + */ + void SetLayoutDesign(LayoutDesign layoutDesign); + /** + * @brief Allow setting the current render window widget without relying on the sending object. + * + * Calling 'SetLayoutDesign' will overwrite the current render window widget but using the public + * layout setter the current render window widget can be defined using the function. + * This is necessary for layouts that work with a specific selected render window widget. + */ + void SetCurrentRenderWindowWidget(QmitkRenderWindowWidget* renderWindowWidget); + + /** + * @brief The default layout shows all render windows in a rectangle. + */ + void SetDefaultLayout(); + /** + * @brief All 2D render windows are spread horizontally above all 3D render windows. + */ + void SetAll2DTop3DBottomLayout(); + /** + * @brief All 2D render windows are spread vertically beneath all 3D render windows. + */ + void SetAll2DLeft3DRightLayout(); + /** + * @brief The current render window is displayed as a single 'full screen' render window. + */ + void SetOneBigLayout(); + /** + * @brief All 2D render windows are spread horizontally, no 3D render windows. + */ + void SetOnly2DHorizontalLayout(); + /** + * @brief All 2D render windows are spread vertically, no 3D render windows. + */ + void SetOnly2DVerticalLayout(); + /** + * @brief The current render window is put above all 3D render windows, which are spread + * horizontally below the current render window. + */ + void SetOneTop3DBottomLayout(); + /** + * @brief The current render window is put beneath all 3D render windows, which are spread + * vertically beneath the current render window. + */ + void SetOneLeft3DRightLayout(); + /** + * @brief All 2D and 3D render windows are spread horizontally. + */ + void SetAllHorizontalLayout(); + /** + * @brief All 2D and 3D render windows are spread vertically. + */ + void SetAllVerticalLayout(); + /** + * @brief Hide the current render window. + */ + void RemoveOneLayout(); + +private: + + QmitkAbstractMultiWidget* m_MultiWidget; + QmitkRenderWindowWidget* m_CurrentRenderWindowWidget; + +}; + +#endif // QMITKMULTIWIDGETLAYOUTMANAGER_H diff --git a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h index 8b9f7ecd3b..3493b2f502 100644 --- a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h @@ -1,154 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKMXNMULTIWIDGET_H #define QMITKMXNMULTIWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" -#include "QmitkRenderWindowWidget.h" - -// mitk core -#include -#include -#include -#include -#include - -// qt -#include - -class QHBoxLayout; -class QVBoxLayout; -class QGridLayout; -class QSpacerItem; -class QmitkRenderWindow; - -namespace mitk -{ - class RenderingManager; -} +#include "QmitkAbstractMultiWidget.h" /** -* @brief The 'QmitkMxNMultiWidget' is a QWidget that is used to display multiple render windows at once. +* @brief The 'QmitkMxNMultiWidget' is a 'QmitkAbstractMultiWidget' that is used to display multiple render windows at once. * Render windows can dynamically be added and removed to change the layout of the multi widget. This -* is done by using the 'ResetLayout'-function to define a layout. This will automatically add or remove +* is done by using the 'SetLayout'-function to define a layout. This will automatically add or remove * the appropriate number of render window widgets. -* Several functions exist to retrieve specific render window(s) (widgets) by their position or name. -* -* The class uses the 'DisplayActionEventBroadcast' and 'DisplayActionEventHandler' classes to -* load a state machine and set an event configuration. PACS mode is used per default. -* Using the 'Synchronize' function the user can enable or disable the synchronization of display action events. -* See 'DisplayActionEventFunctions'-class for the different synchronized and non-synchronized functions used. */ -class MITKQTWIDGETS_EXPORT QmitkMxNMultiWidget : public QWidget +class MITKQTWIDGETS_EXPORT QmitkMxNMultiWidget : public QmitkAbstractMultiWidget { Q_OBJECT public: - using RenderWindowWidgetPointer = std::shared_ptr; - using RenderWindowWidgetMap = std::map>; - using RenderWindowHash = QHash; - QmitkMxNMultiWidget(QWidget* parent = nullptr, - Qt::WindowFlags f = nullptr, - mitk::RenderingManager* renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, - const QString& multiWidgetName = "mxnmulti"); - - ~QmitkMxNMultiWidget() override = default; - - void SetDataStorage(mitk::DataStorage* dataStorage); - void InitializeRenderWindowWidgets(); - - mitk::InteractionEventHandler::Pointer GetInteractionEventHandler() { return m_DisplayActionEventBroadcast.GetPointer(); }; - - void ResetLayout(int row, int column); - void Synchronize(bool synchronized); - void SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); - - RenderWindowWidgetMap GetRenderWindowWidgets() const; - RenderWindowWidgetPointer GetRenderWindowWidget(int row, int column) const; - RenderWindowWidgetPointer GetRenderWindowWidget(const QString& widgetName) const; - RenderWindowHash GetRenderWindows() const; - QmitkRenderWindow* GetRenderWindow(int row, int column) const; - QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const; - - void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget); - RenderWindowWidgetPointer GetActiveRenderWindowWidget() const; - RenderWindowWidgetPointer GetFirstRenderWindowWidget() const; - RenderWindowWidgetPointer GetLastRenderWindowWidget() const; - - unsigned int GetNumberOfRenderWindowWidgets() const; - - void RequestUpdate(const QString& widgetName); - void RequestUpdateAll(); - void ForceImmediateUpdate(const QString& widgetName); - void ForceImmediateUpdateAll(); - - void ActivateAllCrosshairs(bool activate); - const mitk::Point3D GetSelectedPosition(const QString& widgetName) const; + Qt::WindowFlags f = 0, + mitk::RenderingManager* renderingManager = nullptr, + mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, + const QString& multiWidgetName = "mxnmulti"); -public Q_SLOTS: + ~QmitkMxNMultiWidget() = default; + + void InitializeMultiWidget() override; + void MultiWidgetOpened() override; + void MultiWidgetClosed() override; + + QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const override; + QmitkRenderWindow* GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const override; + + void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) override; + + void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) override; + const mitk::Point3D GetSelectedPosition(const QString& widgetName) const override; + + void SetCrosshairVisibility(bool activate) override; + bool GetCrosshairVisibility() const override { return m_CrosshairVisibility; } - void SetSelectedPosition(const QString& widgetName, const mitk::Point3D& newPosition); + void ResetCrosshair() override; + + void SetWidgetPlaneMode(int userMode) override; + +public Q_SLOTS: // mouse events void wheelEvent(QWheelEvent* e) override; - void mousePressEvent(QMouseEvent* e) override; - void moveEvent(QMoveEvent* e) override; Q_SIGNALS: void WheelMoved(QWheelEvent *); void Moved(); private: - void InitializeGUI(); - void InitializeDisplayActionEventHandling(); + void SetLayoutImpl() override; + void SynchronizeImpl() override { } + void SetInteractionSchemeImpl() override { } void CreateRenderWindowWidget(); - void DestroyRenderWindowWidget(); - void FillMultiWidgetLayout(); - - QString GetNameFromIndex(int row, int column) const; - QString GetNameFromIndex(size_t index) const; - - QGridLayout* m_MxNMultiWidgetLayout; - RenderWindowWidgetMap m_RenderWindowWidgets; - - RenderWindowWidgetPointer m_ActiveRenderWindowWidget; - - int m_MultiWidgetRows; - int m_MultiWidgetColumns; - - int m_PlaneMode; - - mitk::RenderingManager* m_RenderingManager; - mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; - QString m_MultiWidgetName; - mitk::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; - std::unique_ptr m_DisplayActionEventHandler; + bool m_CrosshairVisibility; - mitk::DataStorage::Pointer m_DataStorage; }; #endif // QMITKMXNMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkRenderWindow.h b/Modules/QtWidgets/include/QmitkRenderWindow.h index fa8c988407..012fd35019 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindow.h +++ b/Modules/QtWidgets/include/QmitkRenderWindow.h @@ -1,172 +1,170 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66 -#define QMITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66 +#ifndef QMITKRENDERWINDOW_H +#define QMITKRENDERWINDOW_H #include "mitkRenderWindowBase.h" #include "QmitkRenderWindowMenu.h" #include #include #include #include "mitkBaseRenderer.h" #include "mitkInteractionEventConst.h" -class QmitkStdMultiWidget; class QDragEnterEvent; class QDropEvent; class QInputEvent; /** * \ingroup QmitkModule * \brief MITK implementation of the QVTKWidget */ class MITKQTWIDGETS_EXPORT QmitkRenderWindow : public QVTKOpenGLWidget, public mitk::RenderWindowBase { Q_OBJECT public: QmitkRenderWindow( QWidget *parent = nullptr, const QString &name = "unnamed renderwindow", mitk::VtkPropRenderer *renderer = nullptr, mitk::RenderingManager *renderingManager = nullptr, mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard); ~QmitkRenderWindow() override; /** * \brief Whether Qt events should be passed to parent (default: true) * * With introduction of the QVTKWidget the behaviour regarding Qt events changed. * QVTKWidget "accepts" Qt events like mouse clicks (i.e. set an "accepted" flag). * When this flag is set, Qt fininshed handling of this event -- otherwise it is * reached through to the widget's parent. * * This reaching through to the parent was implicitly required by QmitkMaterialWidget / QmitkMaterialShowCase. - *QmitkStdMultiWidget + * * The default behaviour of QmitkRenderWindow is now to clear the "accepted" flag * of Qt events after they were handled by QVTKWidget. This way parents can also * handle events. * * If you don't want this behaviour, call SetResendQtEvents(true) on your render window. */ virtual void SetResendQtEvents(bool resend); // Set Layout Index to define the Layout Type - void SetLayoutIndex(unsigned int layoutIndex); + void SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex); // Get Layout Index to define the Layout Type - unsigned int GetLayoutIndex(); + QmitkRenderWindowMenu::LayoutIndex GetLayoutIndex(); // MenuWidget need to update the Layout Design List when Layout had changed - void LayoutDesignListChanged(int layoutDesignIndex); - - void HideRenderWindowMenu(); + void LayoutDesignListChanged(QmitkRenderWindowMenu::LayoutDesign layoutDesign); // Activate or Deactivate MenuWidget. - void ActivateMenuWidget(bool state, QmitkStdMultiWidget *stdMultiWidget = nullptr); + void ActivateMenuWidget(bool state); bool GetActivateMenuWidgetFlag() { return m_MenuWidgetActivated; } // Get it from the QVTKWidget parent vtkRenderWindow *GetVtkRenderWindow() override { return GetRenderWindow(); } + vtkRenderWindowInteractor *GetVtkRenderWindowInteractor() override { return nullptr; } - void FullScreenMode(bool state); protected: + // overloaded move handler void moveEvent(QMoveEvent *event) override; // overloaded show handler void showEvent(QShowEvent *event) override; // overloaded mouse press handler void mousePressEvent(QMouseEvent *event) override; // overloaded mouse double-click handler void mouseDoubleClickEvent(QMouseEvent *event) override; // overloaded mouse move handler void mouseMoveEvent(QMouseEvent *event) override; // overloaded mouse release handler void mouseReleaseEvent(QMouseEvent *event) override; // overloaded key press handler void keyPressEvent(QKeyEvent *event) override; // overloaded enter handler void enterEvent(QEvent *) override; // overloaded leave handler void leaveEvent(QEvent *) override; // Overloaded resize handler, see decs in QVTKOpenGLWidget. // Basically, we have to ensure the VTK rendering is updated for each change in window size. void resizeGL(int w, int h) Q_DECL_OVERRIDE; /// \brief Simply says we accept the event type. void dragEnterEvent(QDragEnterEvent *event) override; /// \brief If the dropped type is application/x-mitk-datanodes we process the request by converting to mitk::DataNode /// pointers and emitting the NodesDropped signal. void dropEvent(QDropEvent *event) override; #ifndef QT_NO_WHEELEVENT // overload wheel mouse event void wheelEvent(QWheelEvent *) override; #endif void AdjustRenderWindowMenuVisibility(const QPoint &pos); -signals: +Q_SIGNALS: + + void LayoutDesignChanged(QmitkRenderWindowMenu::LayoutDesign); void ResetView(); - // \brief int parameters are enum from QmitkStdMultiWidget - void ChangeCrosshairRotationMode(int); - void SignalLayoutDesignChanged(int layoutDesignIndex); + void CrosshairRotationModeChanged(int); + + void CrosshairVisibilityChanged(bool); void moved(); /// \brief Emits a signal to say that this window has had the following nodes dropped on it. void NodesDropped(QmitkRenderWindow *thisWindow, std::vector nodes); -protected slots: - - void OnChangeLayoutDesign(int layoutDesignIndex); - - void OnWidgetPlaneModeChanged(int); +private Q_SLOTS: void DeferredHideMenu(); private: // Helper Functions to Convert Qt-Events to Mitk-Events mitk::Point2D GetMousePosition(QMouseEvent *me) const; mitk::Point2D GetMousePosition(QWheelEvent *we) const; mitk::InteractionEvent::MouseButtons GetEventButton(QMouseEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QMouseEvent *me) const; mitk::InteractionEvent::ModifierKeys GetModifiers(QInputEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QWheelEvent *we) const; std::string GetKeyLetter(QKeyEvent *ke) const; int GetDelta(QWheelEvent *we) const; + bool m_ResendQtEvents; QmitkRenderWindowMenu *m_MenuWidget; bool m_MenuWidgetActivated; - unsigned int m_LayoutIndex; + QmitkRenderWindowMenu::LayoutIndex m_LayoutIndex; vtkSmartPointer m_InternalRenderWindow; + }; -#endif +#endif // QMITKRENDERWINDOW_H diff --git a/Modules/QtWidgets/include/QmitkRenderWindowMenu.h b/Modules/QtWidgets/include/QmitkRenderWindowMenu.h index fff5f459ad..a28f4c9b43 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowMenu.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowMenu.h @@ -1,342 +1,214 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QmitkRenderWindowMenu_h -#define QmitkRenderWindowMenu_h +#ifndef QMITKRENDERWINDOWMENU_H +#define QMITKRENDERWINDOWMENU_H #if defined(_WIN32) || defined(__APPLE__) #define QMITK_USE_EXTERNAL_RENDERWINDOW_MENU #endif -#include "mitkBaseRenderer.h" -#include +// mitk qtwidgets module +#include "MitkQtWidgetsExports.h" +#include "QmitkMultiWidgetLayoutManager.h" +// mitk core +#include + +// qt #include #include #include #include #include #include #include #include -class QmitkStdMultiWidget; - /** * \ingroup QmitkModule * \brief The QmitkRenderWindowMenu is a popup Widget which shows - * up when the mouse curser enter a QmitkRenderWindow. + * up when the mouse cursor enter a QmitkRenderWindow. * The Menu Widget is located in the right top corner of each * RenderWindow. It includes different settings. For example * the layout design can be changed with the setting button. Switching * between full-screen mode and layout design can be done - * with the full-screen button. Splitting the Widget horizontal or - * vertical as well closing the Widget is not implemented yet. + * with the full-screen button. * The popup Widget can be deactivated with ActivateMenuWidget(false) in * QmitkRenderWindow. * * \sa QmitkRenderWindow - * \sa QmitkStdMultiWidget * */ class MITKQTWIDGETS_EXPORT QmitkRenderWindowMenu : public QWidget { Q_OBJECT public: + + using LayoutIndex = mitk::BaseRenderer::ViewDirection; + using LayoutDesign = QmitkMultiWidgetLayoutManager::LayoutDesign; + QmitkRenderWindowMenu(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr, - mitk::BaseRenderer *b = nullptr, - QmitkStdMultiWidget *mw = nullptr); + mitk::BaseRenderer *b = nullptr); ~QmitkRenderWindowMenu() override; /*! Return visibility of settings menu. The menu is connected with m_SettingsButton and includes layout direction (axial, coronal .. ) and layout design (standard layout, 2D images top, 3D bottom ... ). */ bool GetSettingsMenuVisibilty() { - if (m_Settings == nullptr) + if (m_LayoutActionsMenu == nullptr) return false; else - return m_Settings->isVisible(); + return m_LayoutActionsMenu->isVisible(); } /*! Set layout index. Defines layout direction (axial, coronal, sagital or threeD) of the parent. */ - void SetLayoutIndex(unsigned int layoutIndex); + void SetLayoutIndex(LayoutIndex layoutIndex); /*! Return layout direction of parent (axial, coronal, sagital or threeD) */ - unsigned int GetLayoutIndex() { return m_Layout; } + LayoutIndex GetLayoutIndex() { return m_Layout; } /*! Update list of layout design (standard layout, 2D images top, 3D bottom ..). Set action of current layout design to disable and all other to enable. */ - void UpdateLayoutDesignList(int layoutDesignIndex); + void UpdateLayoutDesignList(LayoutDesign layoutDesign); /*! Move menu widget to correct position (right upper corner). E.g. it is necessary when the full-screen mode is activated.*/ #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU void MoveWidgetToCorrectPos(float opacity); #else void MoveWidgetToCorrectPos(float /*opacity*/); #endif - void ChangeFullScreenMode(bool state); - - void NotifyNewWidgetPlanesMode(int mode); + void ShowMenu(); + void HideMenu(); protected: - /*! Create menu widget. The menu contains five QPushButtons (hori-split, verti-split, full-screen, settings and close - button) - and their signal/slot connection for handling. */ - void CreateMenuWidget(); - - /*! Create settings menu which contains layout direction and the different layout designs. */ - void CreateSettingsWidget(); /*! Reimplemented from QWidget. The paint event is a request to repaint all or part of a widget.*/ void paintEvent(QPaintEvent *event) override; - /*! Update list of layout direction (axial, coronal, sagital or threeD). Set action of currect layout direction - to disable and all other to enable. Normaly the user can switch here between the different layout direction, but - this is not supported yet. */ - void UpdateLayoutList(); + void CreateMenuWidget(); + + /*! Create settings menu which contains layout direction and the different layout designs. */ + void CreateSettingsWidget(); /*! Change Icon of full-screen button depending on full-screen mode. */ void ChangeFullScreenIcon(); - int currentCrosshairRotationMode; - -public slots: - - void SetCrossHairVisibility(bool state); - -signals: +Q_SIGNALS: void ResetView(); // == "global reinit" + void CrosshairVisibilityChanged(bool); + // \brief int parameters are enum from QmitkStdMultiWidget - void ChangeCrosshairRotationMode(int); + void CrosshairRotationModeChanged(int); /*! emit signal, when layout design changed by the setting menu.*/ - void SignalChangeLayoutDesign(int layoutDesign); + void LayoutDesignChanged(LayoutDesign layoutDesign); -public slots: +public Q_SLOTS: - void DeferredHideMenu(); void DeferredShowMenu(); + void DeferredHideMenu(); + /*! This method is responsible for non fluttering of + the renderWindowMenu when mouse cursor moves along the renderWindowMenu*/ void smoothHide(); -protected slots: +protected Q_SLOTS: - /// - /// this function is continously called by a timer + void enterEvent(QEvent * /*e*/) override; + void leaveEvent(QEvent * /*e*/) override; + + /// this function is continuously called by a timer /// to do the auto rotation - /// void AutoRotateNextStep(); - /// + /// this function is invoked when the auto-rotate action /// is clicked - /// void OnAutoRotationActionTriggered(); - void enterEvent(QEvent * /*e*/) override; - void leaveEvent(QEvent * /*e*/) override; void OnTSNumChanged(int); + void OnCrosshairMenuAboutToShow(); + void OnCrosshairVisibilityChanged(bool); void OnCrosshairRotationModeSelected(QAction *); /*! slot for activating/deactivating the full-screen mode. The slot is connected to the clicked() event of m_FullScreenButton. Activating the full-screen maximize the current widget, deactivating restore If layout design changed by the settings - menu, - the full-Screen mode is automatically switch to false. */ + menu, the full-Screen mode is automatically switched to false. */ void OnFullScreenButton(bool checked); /*! Slot for opening setting menu. The slot is connected to the clicked() event of m_SettingsButton. - The settings menu includes differen layout directions (axial, coronal, saggital and 3D) as well all layout design + The settings menu includes different layout directions (axial, coronal, sagittal and 3D) as well all layout design (standard layout, 2D images top, 3D bottom ..)*/ - void OnSettingsButton(bool checked); - - /*! Slot for changing layout design to standard layout. The slot is connected to the triggered() signal of - * m_DefaultLayoutAction. */ - void OnChangeLayoutToDefault(bool); - - /*! Slot for changing layout design to 2D images top, 3D bottom layout. The slot is connected to the triggered() - * signal of m_2DImagesUpLayoutAction. */ - void OnChangeLayoutTo2DImagesUp(bool); - - /*! Slot for changing layout design to 2D images left, 3D right layout. The slot is connected to the triggered() - * signal of m_2DImagesLeftLayoutAction. */ - void OnChangeLayoutTo2DImagesLeft(bool); - - /*! Slot for changing layout to Big 3D layout. The slot is connected to the triggered() signal of m_Big3DLayoutAction. - */ - void OnChangeLayoutToBig3D(bool); - - /*! Slot for changing layout design to Axial plane layout. The slot is connected to the triggered() signal of - * m_Widget1LayoutAction. */ - void OnChangeLayoutToWidget1(bool); - - /*! Slot for changing layout design to Sagittal plane layout. The slot is connected to the triggered() signal of - * m_Widget2LayoutAction. */ - void OnChangeLayoutToWidget2(bool); - - /*! Slot for changing layout design to Coronal plane layout. The slot is connected to the triggered() signal of - * m_Widget3LayoutAction. */ - void OnChangeLayoutToWidget3(bool); + void OnLayoutDesignButton(bool checked); - /*! Slot for changing layout design to Coronal top, 3D bottom layout. The slot is connected to the triggered() signal - * of m_RowWidget3And4LayoutAction. */ - void OnChangeLayoutToRowWidget3And4(bool); - - /*! Slot for changing layout design to Coronal left, 3D right layout. The slot is connected to the triggered() signal - * of m_ColumnWidget3And4LayoutAction. */ - void OnChangeLayoutToColumnWidget3And4(bool); - - /*! Slot for changing layout design to Sagittal top, Coronal n 3D bottom layout. The slot is connected to the - * triggered() signal of m_SmallUpperWidget2Big3and4LayoutAction. */ - void OnChangeLayoutToSmallUpperWidget2Big3and4(bool); - - /*! Slot for changing layout design to Axial n Sagittal left, 3D right layout. The slot is connected to the - * triggered() signal of m_2x2Dand3DWidgetLayoutAction. */ - void OnChangeLayoutTo2x2Dand3DWidget(bool); - - /*! Slot for changing layout design to Axial n 3D left, Sagittal right layout. The slot is connected to the - * triggered() signal of m_Left2Dand3DRight2DLayoutAction. */ - void OnChangeLayoutToLeft2Dand3DRight2D(bool); - - void OnCrossHairMenuAboutToShow(); - -public: - /*! enum for layout direction*/ - enum - { - AXIAL, - SAGITTAL, - CORONAL, - THREE_D - }; - - /*! enum for layout design */ - enum - { - LAYOUT_DEFAULT, - LAYOUT_2DIMAGEUP, - LAYOUT_2DIMAGELEFT, - LAYOUT_BIG3D, - LAYOUT_AXIAL, - LAYOUT_SAGITTAL, - LAYOUT_CORONAL, - LAYOUT_2X2DAND3DWIDGET, - LAYOUT_ROWWIDGET3AND4, - LAYOUT_COLUMNWIDGET3AND4, - LAYOUT_ROWWIDGETSMALL3ANDBIG4, // not in use in this class, but we need it here to synchronize with the - // SdtMultiWidget. - LAYOUT_SMALLUPPERWIDGET2BIGAND4, - LAYOUT_LEFT2DAND3DRIGHT2D - }; - - void ShowMenu(); - void HideMenu(); + void OnSetLayout(LayoutDesign layoutDesign); protected: - QToolButton *m_CrosshairModeButton; - - // QAction* m_ShowHideCrosshairVisibilityAction; - - /*! QPushButton for activating/deactivating full-screen mode*/ - QToolButton *m_FullScreenButton; - - /*! QPushButton for open the settings menu*/ - QToolButton *m_SettingsButton; - - /*! QAction for Default layout design */ - QAction *m_DefaultLayoutAction; - - /*! QAction for 2D images up layout design */ - QAction *m_2DImagesUpLayoutAction; - /*! QAction for 2D images left layout design */ - QAction *m_2DImagesLeftLayoutAction; + QToolButton* m_CrosshairModeButton; - /*! QAction for big 3D layout design */ - QAction *m_Big3DLayoutAction; + QToolButton* m_FullScreenButton; - /*! QAction for big axial layout design */ - QAction *m_Widget1LayoutAction; - - /*! QAction for big saggital layout design */ - QAction *m_Widget2LayoutAction; - - /*! QAction for big coronal layout design */ - QAction *m_Widget3LayoutAction; - - /*! QAction for coronal top, 3D bottom layout design */ - QAction *m_RowWidget3And4LayoutAction; - - /*! QAction for coronal left, 3D right layout design */ - QAction *m_ColumnWidget3And4LayoutAction; - - /*! QAction for sagittal top, coronal n 3D bottom layout design */ - QAction *m_SmallUpperWidget2Big3and4LayoutAction; - - /*! QAction for axial n sagittal left, 3D right layout design */ - QAction *m_2x2Dand3DWidgetLayoutAction; - - /*! QAction for axial n 3D left, sagittal right layout design*/ - QAction *m_Left2Dand3DRight2DLayoutAction; + QToolButton* m_LayoutDesignButton; + QMenu* m_LayoutActionsMenu; + QAction* m_DefaultLayoutAction; + QAction* m_All2DTop3DBottomLayoutAction; + QAction* m_All2DLeft3DRightLayoutAction; + QAction* m_OneBigLayoutAction; + QAction* m_Only2DHorizontalLayoutAction; + QAction* m_Only2DVerticalLayoutAction; + QAction* m_OneTop3DBottomLayoutAction; + QAction* m_OneLeft3DRightLayoutAction; + QAction* m_AllHorizontalLayoutAction; + QAction* m_AllVerticalLayoutAction; + QAction* m_RemoveOneLayoutAction; QLabel *m_TSLabel; - /*! QMenu containg all layout direction and layout design settings.*/ - QMenu *m_Settings; - QMenu *m_CrosshairMenu; - /*! Index of layout direction. 0: axial; 1: saggital; 2: coronal; 3: threeD */ - unsigned int m_Layout; - - /*! Index of layout design. 0: LAYOUT_DEFAULT; 1: LAYOUT_2DIMAGEUP; 2: LAYOUT_2DIMAGELEFT; 3: LAYOUT_BIG3D - 4: LAYOUT_AXIAL; 5: LAYOUT_SAGITTAL; 6: LAYOUT_CORONAL; 7: LAYOUT_2X2DAND3DWIDGET; 8: LAYOUT_ROWWIDGET3AND4; - 9: LAYOUT_COLUMNWIDGET3AND4; 10: LAYOUT_ROWWIDGETSMALL3ANDBIG4; 11: LAYOUT_SMALLUPPERWIDGET2BIGAND4; 12: - LAYOUT_LEFT2DAND3DRIGHT2D */ - unsigned int m_LayoutDesign; - - /*! Store index of old layout design. It is used e.g. for the full-screen mode, when deactivating the mode the former - * layout design will restore.*/ - unsigned int m_OldLayoutDesign; - /*! Flag if full-screen mode is activated or deactivated. */ bool m_FullScreenMode; - bool m_Entered; - private: - mitk::BaseRenderer::Pointer m_Renderer; - QmitkStdMultiWidget *m_MultiWidget; + mitk::BaseRenderer::Pointer m_Renderer; - /// - /// a timer for the auto rotate action - /// - QTimer m_AutoRotationTimer; - QTimer m_HideTimer; + QTimer* m_AutoRotationTimer; + QTimer* m_HideTimer; QWidget *m_Parent; //memory because mode is set to default for slice num = 1 static unsigned int m_DefaultThickMode; + + int m_CrosshairRotationMode; + bool m_CrosshairVisibility; + + LayoutIndex m_Layout; + LayoutDesign m_LayoutDesign; + LayoutDesign m_OldLayoutDesign; + }; -#endif // QmitkRenderWindowMenu_H +#endif // QMITKRENDERWINDOWMENU_H diff --git a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h index d7a4815914..39612fdcde 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h @@ -1,113 +1,119 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWWIDGET_H #define QMITKRENDERWINDOWWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" #include "QmitkRenderWindow.h" // mitk core #include #include #include -#include -#include // qt -#include +#include #include +#include + +class vtkCornerAnnotation; /** -* @brief The 'QmitkRenderWindowWidget' is a QWidget that holds a render window +* @brief The 'QmitkRenderWindowWidget' is a QFrame that holds a render window * and some associates properties, like a crosshair (pointset) and decorations. * Decorations are corner annotation (text and color), frame color or background color * and can be set using this class. -* The 'QmitkRenderWindowWidget' is used inside the 'QmitkMxNMultiWidget', where a map contains -* several render window widgets to create the MxN display. +* The 'QmitkRenderWindowWidget' is used inside a 'QmitkAbstractMultiWidget', where a map contains +* several render window widgets to create the multi widget display. */ -class MITKQTWIDGETS_EXPORT QmitkRenderWindowWidget : public QWidget +class MITKQTWIDGETS_EXPORT QmitkRenderWindowWidget : public QFrame { Q_OBJECT public: QmitkRenderWindowWidget( QWidget* parent = nullptr, const QString& widgetName = "", mitk::DataStorage* dataStorage = nullptr, + mitk::RenderingManager* renderingManager = nullptr, mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard ); ~QmitkRenderWindowWidget() override; void SetDataStorage(mitk::DataStorage* dataStorage); const QString& GetWidgetName() const { return m_WidgetName; }; QmitkRenderWindow* GetRenderWindow() const { return m_RenderWindow; }; mitk::SliceNavigationController* GetSliceNavigationController() const; void RequestUpdate(); void ForceImmediateUpdate(); void SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower); void ShowGradientBackground(bool enable); std::pair GetGradientBackgroundColors() const { return m_GradientBackgroundColors; }; bool IsGradientBackgroundOn() const; void SetDecorationColor(const mitk::Color& color); mitk::Color GetDecorationColor() const { return m_DecorationColor; }; void ShowColoredRectangle(bool show); bool IsColoredRectangleVisible() const; void ShowCornerAnnotation(bool show); bool IsCornerAnnotationVisible() const; void SetCornerAnnotationText(const std::string& cornerAnnotation); std::string GetCornerAnnotationText() const; bool IsRenderWindowMenuActivated() const; void ActivateCrosshair(bool activate); +Q_SIGNALS: + + void MouseEvent(QMouseEvent* e); + private: void InitializeGUI(); void InitializeDecorations(); void SetCrosshair(mitk::Point3D selectedPoint); QString m_WidgetName; QHBoxLayout* m_Layout; mitk::DataStorage* m_DataStorage; - QmitkRenderWindow* m_RenderWindow; - mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; + QmitkRenderWindow* m_RenderWindow; + mitk::DataNode::Pointer m_PointSetNode; mitk::PointSet::Pointer m_PointSet; std::pair m_GradientBackgroundColors; mitk::Color m_DecorationColor; - vtkSmartPointer m_RectangleProp; vtkSmartPointer m_CornerAnnotation; + }; #endif // QMITKRENDERWINDOWWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkStdMultiWidget.h b/Modules/QtWidgets/include/QmitkStdMultiWidget.h index a5c2a2cd7e..03966cdc5b 100644 --- a/Modules/QtWidgets/include/QmitkStdMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkStdMultiWidget.h @@ -1,431 +1,165 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QmitkStdMultiWidget_h -#define QmitkStdMultiWidget_h +#ifndef QMITKSTDMULTIWIDGET_H +#define QMITKSTDMULTIWIDGET_H +// qt widgets module #include "MitkQtWidgetsExports.h" +#include "QmitkAbstractMultiWidget.h" -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include - -class QHBoxLayout; -class QVBoxLayout; -class QGridLayout; -class QSpacerItem; -class QmitkLevelWindowWidget; -class QmitkRenderWindow; -class vtkCornerAnnotation; -class vtkMitkRectangleProp; - -namespace mitk -{ - class RenderingManager; -} - -/// \ingroup QmitkModule -class MITKQTWIDGETS_EXPORT QmitkStdMultiWidget : public QWidget +/** +* @brief The 'QmitkStdMultiWidget' is a 'QmitkAbstractMultiWidget' that is used to display multiple render windows at once. +* Render windows are predefined in a 2x2 design with 3 different 2D view planes and a 3D render window. +*/ +class MITKQTWIDGETS_EXPORT QmitkStdMultiWidget : public QmitkAbstractMultiWidget { Q_OBJECT public: - QmitkStdMultiWidget( - QWidget *parent = nullptr, - Qt::WindowFlags f = nullptr, - mitk::RenderingManager *renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, - const QString &name = "stdmulti"); - ~QmitkStdMultiWidget() override; - - mitk::SliceNavigationController *GetTimeNavigationController(); - - void RequestUpdate(); - - void ForceImmediateUpdate(); - - mitk::MouseModeSwitcher *GetMouseModeSwitcher(); - - QmitkRenderWindow *GetRenderWindow1() const; - - QmitkRenderWindow *GetRenderWindow2() const; - - QmitkRenderWindow *GetRenderWindow3() const; - - QmitkRenderWindow *GetRenderWindow4() const; - const mitk::Point3D GetCrossPosition() const; + QmitkStdMultiWidget(QWidget *parent = nullptr, + Qt::WindowFlags f = 0, + mitk::RenderingManager *renderingManager = nullptr, + mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, + const QString &name = "stdmulti"); - void EnablePositionTracking(); - - void DisablePositionTracking(); + ~QmitkStdMultiWidget() override; - int GetLayout() const; + virtual void InitializeMultiWidget() override; - bool GetGradientBackgroundFlag() const; + virtual QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const override; + virtual QmitkRenderWindow* GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const override; - /*! - \brief Access node of widget plane 1 - \return DataNode holding widget plane 1 - */ - mitk::DataNode::Pointer GetWidgetPlane1(); - /*! - \brief Access node of widget plane 2 - \return DataNode holding widget plane 2 - */ - mitk::DataNode::Pointer GetWidgetPlane2(); - /*! - \brief Access node of widget plane 3 - \return DataNode holding widget plane 3 - */ - mitk::DataNode::Pointer GetWidgetPlane3(); - /*! - \brief Convenience method to access node of widget planes - \param id number of widget plane to be returned - \return DataNode holding widget plane 3 - */ - mitk::DataNode::Pointer GetWidgetPlane(int id); + virtual void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) override; + virtual const mitk::Point3D GetSelectedPosition(const QString& widgetName) const override; - bool IsColoredRectanglesEnabled() const; + virtual void SetCrosshairVisibility(bool) override; + virtual bool GetCrosshairVisibility() const override; - bool IsDepartmentLogoEnabled() const; + virtual void ResetCrosshair() override; - void InitializeWidget(); + virtual void SetWidgetPlaneMode(int mode) override; - /// called when the StdMultiWidget is closed to remove the 3 widget planes and the helper node from the DataStorage - void RemovePlanesFromDataStorage(); + mitk::SliceNavigationController* GetTimeNavigationController(); void AddPlanesToDataStorage(); - - void SetDataStorage(mitk::DataStorage *ds); + void RemovePlanesFromDataStorage(); /** \brief Listener to the CrosshairPositionEvent Ensures the CrosshairPositionEvent is handled only once and at the end of the Qt-Event loop */ void HandleCrosshairPositionEvent(); - /// activate Menu Widget. true: activated, false: deactivated - void ActivateMenuWidget(bool state); - - bool IsMenuWidgetEnabled() const; - - void SetCornerAnnotationVisibility(bool visibility); + /** + * @brief Convenience method to get a render window widget. + * @param Number of the widget (0-3) + * @return The render window widget + */ + QmitkRenderWindow* GetRenderWindow(unsigned int number) const; + QmitkRenderWindow* GetRenderWindow1() const; + QmitkRenderWindow* GetRenderWindow2() const; + QmitkRenderWindow* GetRenderWindow3() const; + QmitkRenderWindow* GetRenderWindow4() const; - bool IsCornerAnnotationVisible(void) const; + /** + * @brief Convenience method to get a widget plane. + * @param Number of the widget plane (1-3) + * @return The widget plane as data node + */ + mitk::DataNode::Pointer GetWidgetPlane(unsigned int number) const; + mitk::DataNode::Pointer GetWidgetPlane1() const; + mitk::DataNode::Pointer GetWidgetPlane2() const; + mitk::DataNode::Pointer GetWidgetPlane3() const; -protected: - void UpdateAllWidgets(); + /** + * @brief SetDecorationColor Set the color of the decoration of the 4 widgets. + * + * This is used to color the frame of the renderwindow and the corner annatation. + * For the first 3 widgets, this color is a property of the helper object nodes + * which contain the respective plane geometry. For widget 4, this is a member, + * since there is no data node for this widget. + */ + void SetDecorationColor(unsigned int widgetNumber, mitk::Color color); + /** + * @brief GetDecorationColorForWidget Get the color for annotation, crosshair and rectangle. + * @param widgetNumber Number of the renderwindow (0-3). + * @return Color in mitk format. + */ + mitk::Color GetDecorationColor(unsigned int widgetNumber); - void HideAllWidgetToolbars(); +public Q_SLOTS: -public slots: + // mouse events + virtual void mousePressEvent(QMouseEvent*) override; + virtual void moveEvent(QMoveEvent* e) override; + virtual void wheelEvent(QWheelEvent* e) override; /// Receives the signal from HandleCrosshairPositionEvent, executes the StatusBar update void HandleCrosshairPositionEventDelayed(); - void changeLayoutTo2DImagesUp(); - - void changeLayoutTo2DImagesLeft(); - - void changeLayoutToDefault(); - - void changeLayoutToBig3D(); - - void changeLayoutToWidget1(); - - void changeLayoutToWidget2(); - - void changeLayoutToWidget3(); - - void changeLayoutToRowWidget3And4(); - - void changeLayoutToColumnWidget3And4(); - - void changeLayoutToRowWidgetSmall3andBig4(); - - void changeLayoutToSmallUpperWidget2Big3and4(); - - void changeLayoutTo2x2Dand3DWidget(); - - void changeLayoutToLeft2Dand3DRight2D(); - - /** Changes the layout to one 2D window up and a 3D window down. - * The 2D window can be defined by its id (1-3). If MITK default - * settings were not changed, 1 is axial, 2 is sagittal and 3 is coronal. - */ - void changeLayoutTo2DUpAnd3DDown(unsigned int id2Dwindow = 2); - void Fit(); - void InitPositionTracking(); - void AddDisplayPlaneSubTree(); - void EnableStandardLevelWindow(); - - void DisableStandardLevelWindow(); - - bool InitializeStandardViews(const mitk::Geometry3D *geometry); - - void wheelEvent(QWheelEvent *e) override; - - void mousePressEvent(QMouseEvent *e) override; - - void moveEvent(QMoveEvent *e) override; - void EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p); - void MoveCrossToPosition(const mitk::Point3D &newPosition); - - // void EnableNavigationControllerEventListening(); - - // void DisableNavigationControllerEventListening(); - - void EnableGradientBackground(); - - void DisableGradientBackground(); - - void EnableDepartmentLogo(); - - void DisableDepartmentLogo(); - - void EnableColoredRectangles(); - - void DisableColoredRectangles(); - void SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer = nullptr); void SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer = nullptr); - void SetWidgetPlanesLocked(bool locked); - - void SetWidgetPlanesRotationLocked(bool locked); - - void SetWidgetPlanesRotationLinked(bool link); - - void SetWidgetPlaneMode(int mode); - - void SetGradientBackgroundColors(const mitk::Color &upper, const mitk::Color &lower); - - void SetDepartmentLogo(const char *path); - - void SetWidgetPlaneModeToSlicing(bool activate); - - void SetWidgetPlaneModeToRotation(bool activate); - - void SetWidgetPlaneModeToSwivel(bool activate); - - void OnLayoutDesignChanged(int layoutDesignIndex); - - void ResetCrosshair(); - -signals: +Q_SIGNALS: - void LeftMouseClicked(mitk::Point3D pointValue); void WheelMoved(QWheelEvent *); - void WidgetPlanesRotationLinked(bool); - void WidgetPlanesRotationEnabled(bool); - void ViewsInitialized(); - void WidgetPlaneModeSlicing(bool); - void WidgetPlaneModeRotation(bool); - void WidgetPlaneModeSwivel(bool); - void WidgetPlaneModeChange(int); - void WidgetNotifyNewCrossHairMode(int); void Moved(); -public: - /** Define RenderWindow (public)*/ - QmitkRenderWindow *mitkWidget1; - QmitkRenderWindow *mitkWidget2; - QmitkRenderWindow *mitkWidget3; - QmitkRenderWindow *mitkWidget4; - QmitkLevelWindowWidget *levelWindowWidget; - /********************************/ - - enum - { - PLANE_MODE_SLICING = 0, - PLANE_MODE_ROTATION, - PLANE_MODE_SWIVEL - }; - enum - { - LAYOUT_DEFAULT = 0, - LAYOUT_2D_IMAGES_UP, - LAYOUT_2D_IMAGES_LEFT, - LAYOUT_BIG_3D, - LAYOUT_WIDGET1, - LAYOUT_WIDGET2, - LAYOUT_WIDGET3, - LAYOUT_2X_2D_AND_3D_WIDGET, - LAYOUT_ROW_WIDGET_3_AND_4, - LAYOUT_COLUMN_WIDGET_3_AND_4, - LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4, - LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4, - LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET, - LAYOUT_2D_UP_AND_3D_DOWN - }; - - enum - { - AXIAL, - SAGITTAL, - CORONAL, - THREE_D - }; +private: - /** - * @brief SetCornerAnnotation Create a corner annotation for a widget. - * @param text The text of the annotation. - * @param color The color. - * @param widgetNumber The widget (0-3). - */ - void SetDecorationProperties(std::string text, mitk::Color color, int widgetNumber); - /** - * @brief GetRenderWindow convinience method to get a widget. - * @param number of the widget (0-3) - * @return The renderwindow widget. - */ - QmitkRenderWindow *GetRenderWindow(unsigned int number); + virtual void SetLayoutImpl() override; + virtual void SynchronizeImpl() override { } + virtual void SetInteractionSchemeImpl() override { } - /** - * @brief SetGradientBackgroundColorForRenderWindow background for a widget. - * - * If two different input colors are, a gradient background is generated. - * - * @param upper Upper color of the gradient background. - * @param lower Lower color of the gradient background. - * @param widgetNumber The widget (0-3). - */ - void SetGradientBackgroundColorForRenderWindow(const mitk::Color &upper, - const mitk::Color &lower, - unsigned int widgetNumber); + void CreateRenderWindowWidgets(); - /** - * @brief GetDecorationColorForWidget Get the color for annotation, crosshair and rectangle. - * @param widgetNumber Number of the renderwindow (0-3). - * @return Color in mitk format. - */ - mitk::Color GetDecorationColor(unsigned int widgetNumber); + mitk::SliceNavigationController* m_TimeNavigationController; /** - * @brief SetDecorationColor Set the color of the decoration of the 4 widgets. - * - * This is used to color the frame of the renderwindow and the corner annatation. - * For the first 3 widgets, this color is a property of the helper object nodes - * which contain the respective plane geometry. For widget 4, this is a member, - * since there is no data node for this widget. - */ - void SetDecorationColor(unsigned int widgetNumber, mitk::Color color); - - /** - * @brief GetCornerAnnotationText Getter for corner annotation text. - * @param widgetNumber the widget number (0-3). - * @return The text in the corner annotation. - */ - std::string GetCornerAnnotationText(unsigned int widgetNumber); - - /** - * @brief GetGradientColors Getter for gradientbackground colors. - * @param widgetNumber the widget number (0-3). - * @return A pair of colors. First: upper, second: lower. - */ - std::pair GetGradientColors(unsigned int widgetNumber); - -protected: - QHBoxLayout *QmitkStdMultiWidgetLayout; - - int m_Layout; - int m_PlaneMode; - - mitk::RenderingManager *m_RenderingManager; - - mitk::LogoAnnotation::Pointer m_LogoRendering; - - bool m_GradientBackgroundFlag; - - mitk::MouseModeSwitcher::Pointer m_MouseModeSwitcher; - mitk::SliceNavigationController *m_TimeNavigationController; - - mitk::DataStorage::Pointer m_DataStorage; - - /** - * @brief m_PlaneNode1 the 3 helper objects which contain the plane geometry. - */ + * @brief The 3 helper objects which contain the plane geometry. + */ mitk::DataNode::Pointer m_PlaneNode1; mitk::DataNode::Pointer m_PlaneNode2; mitk::DataNode::Pointer m_PlaneNode3; + /** * @brief m_ParentNodeForGeometryPlanes This helper object is added to the datastorage * and contains the 3 planes for displaying the image geometry (crosshair and 3D planes). */ mitk::DataNode::Pointer m_ParentNodeForGeometryPlanes; /** * @brief m_DecorationColorWidget4 color for annotation and rectangle of widget 4. * * For other widgets1-3, the color is a property of the respective data node. * There is no node for widget 4, hence, we need an extra member. */ mitk::Color m_DecorationColorWidget4; - /** - * @brief m_GradientBackgroundColors Contains the colors of the gradient background. - * - */ - std::pair m_GradientBackgroundColors[4]; - - QSplitter *m_MainSplit; - QSplitter *m_LayoutSplit; - QSplitter *m_SubSplit1; - QSplitter *m_SubSplit2; - - QWidget *mitkWidget1Container; - QWidget *mitkWidget2Container; - QWidget *mitkWidget3Container; - QWidget *mitkWidget4Container; - - vtkSmartPointer m_CornerAnnotations[4]; - vtkSmartPointer m_RectangleProps[4]; - bool m_PendingCrosshairPositionEvent; - bool m_CrosshairNavigationEnabled; - /** - * @brief CreateCornerAnnotation helper method to create a corner annotation. - * @param text of the annotation. - * @param color of the annotation. - * @return the complete CornerAnnotation. - */ - vtkSmartPointer CreateCornerAnnotation(std::string text, mitk::Color color); - /** - * @brief FillGradientBackgroundWithBlack Internal helper method to initialize the - * gradient background colors with black. - */ - void FillGradientBackgroundWithBlack(); }; -#endif /*QmitkStdMultiWidget_h*/ + +#endif // QMITKSTDMULTIWIDGET_H diff --git a/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp b/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp new file mode 100644 index 0000000000..7c972fe8a3 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp @@ -0,0 +1,455 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// mitk qt widgets module +#include "QmitkAbstractMultiWidget.h" +#include "QmitkLevelWindowWidget.h" +#include "QmitkMultiWidgetLayoutManager.h" +#include "QmitkRenderWindowWidget.h" + +// mitk core +#include +#include +#include +#include +#include + +// qt +#include + +// c++ +#include + +struct QmitkAbstractMultiWidget::Impl final +{ + Impl(QmitkAbstractMultiWidget* multiWidget, + mitk::RenderingManager* renderingManager, + mitk::BaseRenderer::RenderingMode::Type renderingMode, + const QString& multiWidgetName); + + void SetDataStorage(mitk::DataStorage* dataStorage) + { + if (dataStorage == m_DataStorage) + { + return; + } + + m_DataStorage = dataStorage; + // set new data storage for the render window widgets + for (const auto& renderWindowWidget : m_RenderWindowWidgets) + { + renderWindowWidget.second->SetDataStorage(m_DataStorage); + } + } + + void Synchronize(bool synchronized) + { + auto allObserverTags = m_DisplayActionEventHandler->GetAllObserverTags(); + for (auto observerTag : allObserverTags) + { + m_DisplayActionEventHandler->DisconnectObserver(observerTag); + } + + if (synchronized) + { + mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); + } + else + { + mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveSenderCameraAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ZoomSenderCameraAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); + } + + // use the standard 'set level window' action for both modes + mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::SetLevelWindowAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetLevelWindowEvent(nullptr, mitk::ScalarType(), mitk::ScalarType()), actionFunction); + } + + void InitializeDisplayActionEventHandling() + { + m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); + m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); + m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigPACS.xml"); + + m_DisplayActionEventHandler = std::make_unique(); + m_DisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); + + Synchronize(true); + } + + mitk::DataStorage::Pointer m_DataStorage; + + mitk::RenderingManager* m_RenderingManager; + mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; + QString m_MultiWidgetName; + + RenderWindowWidgetMap m_RenderWindowWidgets; + RenderWindowWidgetPointer m_ActiveRenderWindowWidget; + + int m_MultiWidgetRows; + int m_MultiWidgetColumns; + + // interaction + mitk::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; + std::unique_ptr m_DisplayActionEventHandler; + QmitkMultiWidgetLayoutManager* m_LayoutManager; +}; + +QmitkAbstractMultiWidget::Impl::Impl(QmitkAbstractMultiWidget* multiWidget, + mitk::RenderingManager* renderingManager, + mitk::BaseRenderer::RenderingMode::Type renderingMode, + const QString& multiWidgetName) + : m_DataStorage(nullptr) + , m_RenderingManager(renderingManager) + , m_RenderingMode(renderingMode) + , m_MultiWidgetName(multiWidgetName) + , m_MultiWidgetRows(0) + , m_MultiWidgetColumns(0) + , m_DisplayActionEventBroadcast(nullptr) + , m_DisplayActionEventHandler(nullptr) + , m_LayoutManager(new QmitkMultiWidgetLayoutManager(multiWidget)) +{ + InitializeDisplayActionEventHandling(); +} + +QmitkAbstractMultiWidget::QmitkAbstractMultiWidget(QWidget* parent, + Qt::WindowFlags f/* = 0*/, + mitk::RenderingManager* renderingManager/* = nullptr*/, + mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, + const QString& multiWidgetName/* = "multiwidget"*/) + : QWidget(parent, f) + , m_Impl(std::make_unique(this, renderingManager, renderingMode, multiWidgetName)) +{ + // nothing here +} + +QmitkAbstractMultiWidget::~QmitkAbstractMultiWidget() { } + +void QmitkAbstractMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) +{ + m_Impl->SetDataStorage(dataStorage); +} + +mitk::DataStorage* QmitkAbstractMultiWidget::GetDataStorage() const +{ + return m_Impl->m_DataStorage; +} + +mitk::RenderingManager* QmitkAbstractMultiWidget::GetRenderingManager() const +{ + // use the global rendering manager if none was specified + if (m_Impl->m_RenderingManager == nullptr) + { + return mitk::RenderingManager::GetInstance(); + } + + return m_Impl->m_RenderingManager; +} + +int QmitkAbstractMultiWidget::GetRowCount() const +{ + return m_Impl->m_MultiWidgetRows; +} + +int QmitkAbstractMultiWidget::GetColumnCount() const +{ + return m_Impl->m_MultiWidgetColumns; +} + +void QmitkAbstractMultiWidget::SetLayout(int row, int column) +{ + m_Impl->m_MultiWidgetRows = row; + m_Impl->m_MultiWidgetColumns = column; + SetLayoutImpl(); +} + +void QmitkAbstractMultiWidget::Synchronize(bool synchronized) +{ + m_Impl->Synchronize(synchronized); + SynchronizeImpl(); +} + +void QmitkAbstractMultiWidget::SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) +{ + auto interactionSchemeSwitcher = mitk::InteractionSchemeSwitcher::New(); + auto interactionEventHandler = GetInteractionEventHandler(); + try + { + interactionSchemeSwitcher->SetInteractionScheme(interactionEventHandler, scheme); + } + catch (const mitk::Exception&) + { + return; + } + + SetInteractionSchemeImpl(); +} + +mitk::InteractionEventHandler* QmitkAbstractMultiWidget::GetInteractionEventHandler() +{ + return m_Impl->m_DisplayActionEventBroadcast.GetPointer(); +} + +QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::GetRenderWindowWidgets() const +{ + return m_Impl->m_RenderWindowWidgets; +} + +QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::Get2DRenderWindowWidgets() const +{ + RenderWindowWidgetMap renderWindowWidgets2D; + + auto renderWindowWidgets = GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + auto renderWindow = renderWindowWidget.second->GetRenderWindow(); + if(mitk::BaseRenderer::Standard2D == mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow())->GetMapperID()) + { + renderWindowWidgets2D.insert(std::make_pair(renderWindowWidget.first, renderWindowWidget.second)); + } + } + + return renderWindowWidgets2D; +} + +QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::Get3DRenderWindowWidgets() const +{ + RenderWindowWidgetMap renderWindowWidgets3D; + + auto renderWindowWidgets = GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + auto renderWindow = renderWindowWidget.second->GetRenderWindow(); + if (mitk::BaseRenderer::Standard3D == mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow())->GetMapperID()) + { + renderWindowWidgets3D.insert(std::make_pair(renderWindowWidget.first, renderWindowWidget.second)); + } + } + + return renderWindowWidgets3D; +} + +QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(int row, int column) const +{ + return GetRenderWindowWidget(GetNameFromIndex(row, column)); +} + +QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(const QString& widgetName) const +{ + RenderWindowWidgetMap::const_iterator it = m_Impl->m_RenderWindowWidgets.find(widgetName); + if (it != m_Impl->m_RenderWindowWidgets.end()) + { + return it->second; + } + + return nullptr; +} + +QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(const QmitkRenderWindow* renderWindow) const +{ + auto renderWindowWidgets = GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + if (renderWindowWidget.second->GetRenderWindow() == renderWindow) + { + return renderWindowWidget.second; + } + } + + return nullptr; +} + +QmitkAbstractMultiWidget::RenderWindowHash QmitkAbstractMultiWidget::GetRenderWindows() const +{ + RenderWindowHash result; + // create QHash on demand + auto renderWindowWidgets = GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); + } + + return result; +} + +QmitkRenderWindow* QmitkAbstractMultiWidget::GetRenderWindow(int row, int column) const +{ + return GetRenderWindow(GetNameFromIndex(row, column)); +} + +QmitkRenderWindow* QmitkAbstractMultiWidget::GetRenderWindow(const QString& widgetName) const +{ + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->GetRenderWindow(); + } + + return nullptr; +} + +void QmitkAbstractMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) +{ + m_Impl->m_ActiveRenderWindowWidget = activeRenderWindowWidget; + emit ActiveRenderWindowChanged(); +} + +QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetActiveRenderWindowWidget() const +{ + return m_Impl->m_ActiveRenderWindowWidget; +} + +QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetFirstRenderWindowWidget() const +{ + if (!m_Impl->m_RenderWindowWidgets.empty()) + { + return m_Impl->m_RenderWindowWidgets.begin()->second; + } + else + { + return nullptr; + } +} + +QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetLastRenderWindowWidget() const +{ + if (!m_Impl->m_RenderWindowWidgets.empty()) + { + return m_Impl->m_RenderWindowWidgets.rbegin()->second; + } + else + { + return nullptr; + } +} + +QString QmitkAbstractMultiWidget::GetNameFromIndex(int row, int column) const +{ + if (0 <= row && m_Impl->m_MultiWidgetRows > row && 0 <= column && m_Impl->m_MultiWidgetColumns > column) + { + return GetNameFromIndex(row * m_Impl->m_MultiWidgetColumns + column); + } + + return QString(); +} + +QString QmitkAbstractMultiWidget::GetNameFromIndex(size_t index) const +{ + if (index <= m_Impl->m_RenderWindowWidgets.size()) + { + return m_Impl->m_MultiWidgetName + ".widget" + QString::number(index); + } + + return QString(); +} + +unsigned int QmitkAbstractMultiWidget::GetNumberOfRenderWindowWidgets() const +{ + return m_Impl->m_RenderWindowWidgets.size(); +} + +void QmitkAbstractMultiWidget::RequestUpdate(const QString& widgetName) +{ + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->RequestUpdate(); + } +} + +void QmitkAbstractMultiWidget::RequestUpdateAll() +{ + for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) + { + renderWindowWidget.second->RequestUpdate(); + } +} + +void QmitkAbstractMultiWidget::ForceImmediateUpdate(const QString& widgetName) +{ + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->ForceImmediateUpdate(); + } +} + +void QmitkAbstractMultiWidget::ForceImmediateUpdateAll() +{ + for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) + { + renderWindowWidget.second->ForceImmediateUpdate(); + } +} + +void QmitkAbstractMultiWidget::ActivateMenuWidget(bool state) +{ + for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) + { + auto renderWindow = renderWindowWidget.second->GetRenderWindow(); + renderWindow->ActivateMenuWidget(state); + } +} + +bool QmitkAbstractMultiWidget::IsMenuWidgetEnabled() const +{ + return m_Impl->m_ActiveRenderWindowWidget->GetRenderWindow()->GetActivateMenuWidgetFlag(); +} + +QmitkMultiWidgetLayoutManager* QmitkAbstractMultiWidget::GetMultiWidgetLayoutManager() const +{ + return m_Impl->m_LayoutManager; +} + +void QmitkAbstractMultiWidget::AddRenderWindowWidget(const QString& widgetName, RenderWindowWidgetPointer renderWindowWidget) +{ + m_Impl->m_RenderWindowWidgets.insert(std::make_pair(widgetName, renderWindowWidget)); +} + +void QmitkAbstractMultiWidget::RemoveRenderWindowWidget() +{ + auto iterator = m_Impl->m_RenderWindowWidgets.find(GetNameFromIndex(GetRenderWindowWidgets().size() - 1)); + if (iterator == m_Impl->m_RenderWindowWidgets.end()) + { + return; + } + + // disconnect each signal of this render window widget + RenderWindowWidgetPointer renderWindowWidgetToRemove = iterator->second; + disconnect(renderWindowWidgetToRemove.get(), 0, 0, 0); + + // erase the render window from the map + m_Impl->m_RenderWindowWidgets.erase(iterator); +} diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp index f4118e3f52..532fac175c 100644 --- a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp +++ b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp @@ -1,105 +1,113 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMultiWidgetConfigurationToolBar.h" -QmitkMultiWidgetConfigurationToolBar::QmitkMultiWidgetConfigurationToolBar() - : QToolBar() +// mitk qt widgets module +#include "QmitkAbstractMultiWidget.h" +#include "QmitkMultiWidgetLayoutSelectionWidget.h" + +QmitkMultiWidgetConfigurationToolBar::QmitkMultiWidgetConfigurationToolBar(QmitkAbstractMultiWidget* multiWidget) + : QToolBar(multiWidget) + , m_MultiWidget(multiWidget) { QToolBar::setOrientation(Qt::Vertical); QToolBar::setIconSize(QSize(17, 17)); InitializeToolBar(); } QmitkMultiWidgetConfigurationToolBar::~QmitkMultiWidgetConfigurationToolBar() { // nothing here } void QmitkMultiWidgetConfigurationToolBar::InitializeToolBar() { // create popup to show a widget to modify the multi widget layout m_LayoutSelectionPopup = new QmitkMultiWidgetLayoutSelectionWidget(this); m_LayoutSelectionPopup->hide(); AddButtons(); connect(m_LayoutSelectionPopup, &QmitkMultiWidgetLayoutSelectionWidget::LayoutSet, this, &QmitkMultiWidgetConfigurationToolBar::LayoutSet); } void QmitkMultiWidgetConfigurationToolBar::AddButtons() { QAction* setLayoutAction = new QAction(QIcon(":/Qmitk/mwLayout.png"), tr("Set multi widget layout"), this); connect(setLayoutAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSetLayout); QToolBar::addAction(setLayoutAction); m_SynchronizeAction = new QAction(QIcon(":/Qmitk/mwSynchronized.png"), tr("Desynchronize render windows"), this); m_SynchronizeAction->setCheckable(true); m_SynchronizeAction->setChecked(true); connect(m_SynchronizeAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSynchronize); QToolBar::addAction(m_SynchronizeAction); m_InteractionSchemeChangeAction = new QAction(QIcon(":/Qmitk/mwMITK.png"), tr("Change to PACS interaction"), this); m_InteractionSchemeChangeAction->setCheckable(true); m_InteractionSchemeChangeAction->setChecked(false); connect(m_InteractionSchemeChangeAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnInteractionSchemeChanged); QToolBar::addAction(m_InteractionSchemeChangeAction); } void QmitkMultiWidgetConfigurationToolBar::OnSetLayout() { - m_LayoutSelectionPopup->setWindowFlags(Qt::Popup); - m_LayoutSelectionPopup->move(this->cursor().pos().x() - m_LayoutSelectionPopup->width(), this->cursor().pos().y()); - m_LayoutSelectionPopup->show(); + if (nullptr != m_MultiWidget) + { + m_LayoutSelectionPopup->setWindowFlags(Qt::Popup); + m_LayoutSelectionPopup->move(this->cursor().pos().x() - m_LayoutSelectionPopup->width(), this->cursor().pos().y()); + m_LayoutSelectionPopup->show(); + } } void QmitkMultiWidgetConfigurationToolBar::OnSynchronize() { bool synchronized = m_SynchronizeAction->isChecked(); if (synchronized) { m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwSynchronized.png")); m_SynchronizeAction->setText(tr("Desynchronize render windows")); } else { m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwDesynchronized.png")); m_SynchronizeAction->setText(tr("Synchronize render windows")); } m_SynchronizeAction->setChecked(synchronized); emit Synchronized(synchronized); } void QmitkMultiWidgetConfigurationToolBar::OnInteractionSchemeChanged() { bool PACSInteractionScheme = m_InteractionSchemeChangeAction->isChecked(); if (PACSInteractionScheme) { m_InteractionSchemeChangeAction->setIcon(QIcon(":/Qmitk/mwPACS.png")); m_InteractionSchemeChangeAction->setText(tr("Change to MITK interaction")); emit InteractionSchemeChanged(mitk::InteractionSchemeSwitcher::PACSStandard); } else { m_InteractionSchemeChangeAction->setIcon(QIcon(":/Qmitk/mwMITK.png")); m_InteractionSchemeChangeAction->setText(tr("Change to PACS interaction")); emit InteractionSchemeChanged(mitk::InteractionSchemeSwitcher::MITKStandard); } m_InteractionSchemeChangeAction->setChecked(PACSInteractionScheme); } diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutManager.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutManager.cpp new file mode 100644 index 0000000000..5e42241b81 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutManager.cpp @@ -0,0 +1,545 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkMultiWidgetLayoutManager.h" + +#include +#include +#include +#include + +// qt +#include +#include + +QmitkMultiWidgetLayoutManager::QmitkMultiWidgetLayoutManager(QmitkAbstractMultiWidget* multiwidget) + : QObject(multiwidget) + , m_MultiWidget(multiwidget) + , m_CurrentRenderWindowWidget(nullptr) +{ + // nothing here +} + +void QmitkMultiWidgetLayoutManager::SetLayoutDesign(LayoutDesign layoutDesign) +{ + if (nullptr == m_MultiWidget) + { + return; + } + + // retrieve the render window name from the sending render window + auto renderWindow = dynamic_cast(QObject::sender()); + m_CurrentRenderWindowWidget = m_MultiWidget->GetRenderWindowWidget(renderWindow).get(); + + switch (layoutDesign) + { + case LayoutDesign::DEFAULT: + { + SetDefaultLayout(); + break; + } + case LayoutDesign::ALL_2D_TOP_3D_BOTTOM: + { + SetAll2DTop3DBottomLayout(); + break; + } + case LayoutDesign::ALL_2D_LEFT_3D_RIGHT: + { + SetAll2DLeft3DRightLayout(); + break; + } + case LayoutDesign::ONE_BIG: + { + SetOneBigLayout(); + break; + } + case LayoutDesign::ONLY_2D_HORIZONTAL: + { + SetOnly2DHorizontalLayout(); + break; + } + case LayoutDesign::ONLY_2D_VERTICAL: + { + SetOnly2DVerticalLayout(); + break; + } + case LayoutDesign::ONE_TOP_3D_BOTTOM: + { + SetOneTop3DBottomLayout(); + break; + } + case LayoutDesign::ONE_LEFT_3D_RIGHT: + { + SetOneLeft3DRightLayout(); + break; + } + case LayoutDesign::ALL_HORIZONTAL: + { + SetAllHorizontalLayout(); + break; + } + case LayoutDesign::ALL_VERTICAL: + { + SetAllVerticalLayout(); + break; + } + case LayoutDesign::REMOVE_ONE: + { + RemoveOneLayout(); + break; + } + case LayoutDesign::NONE: + { + break; + } + }; +} + +void QmitkMultiWidgetLayoutManager::SetCurrentRenderWindowWidget(QmitkRenderWindowWidget* renderWindowWidget) +{ + m_CurrentRenderWindowWidget = renderWindowWidget; +} + +void QmitkMultiWidgetLayoutManager::SetDefaultLayout() +{ + MITK_INFO << "Set default layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(Qt::Vertical, m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + QList splitterSizeRow; + for (int row = 0; row < m_MultiWidget->GetRowCount(); ++row) + { + splitterSizeRow.push_back(1000); + + QList splitterSizeColumn; + auto splitter = new QSplitter(mainSplit); + for (int column = 0; column < m_MultiWidget->GetColumnCount(); ++column) + { + splitterSizeColumn.push_back(1000); + auto renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(row, column); + splitter->addWidget(renderWindowWidget.get()); + renderWindowWidget->show(); + } + splitter->setSizes(splitterSizeColumn); + } + + mainSplit->setSizes(splitterSizeRow); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::DEFAULT); + } +} + +void QmitkMultiWidgetLayoutManager::SetAll2DTop3DBottomLayout() +{ + MITK_INFO << "Set all 2D top and 3D bottom layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(Qt::Vertical, m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + auto subSplit2D = new QSplitter(mainSplit); + QList splitterSize; + auto all2DRenderWindowWidgets = m_MultiWidget->Get2DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all2DRenderWindowWidgets) + { + subSplit2D->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + subSplit2D->setSizes(splitterSize); + + auto subSplit3D = new QSplitter(mainSplit); + splitterSize.clear(); + auto all3DRenderWindowWidgets = m_MultiWidget->Get3DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all3DRenderWindowWidgets) + { + subSplit3D->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + subSplit3D->setSizes(splitterSize); + + // set size for main splitter + splitterSize.clear(); + splitterSize.push_back(600); + splitterSize.push_back(1000); + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ALL_2D_TOP_3D_BOTTOM); + } +} + +void QmitkMultiWidgetLayoutManager::SetAll2DLeft3DRightLayout() +{ + MITK_INFO << "Set all 2D left and 3D right layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + auto subSplit2D = new QSplitter(Qt::Vertical, mainSplit); + QList splitterSize; + auto all2DRenderWindowWidgets = m_MultiWidget->Get2DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all2DRenderWindowWidgets) + { + subSplit2D->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + subSplit2D->setSizes(splitterSize); + + auto subSplit3D = new QSplitter(mainSplit); + splitterSize.clear(); + auto all3DRenderWindowWidgets = m_MultiWidget->Get3DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all3DRenderWindowWidgets) + { + subSplit3D->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + subSplit3D->setSizes(splitterSize); + + // set size for main splitter + splitterSize.clear(); + splitterSize.push_back(600); + splitterSize.push_back(1000); + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ALL_2D_LEFT_3D_RIGHT); + } +} + +void QmitkMultiWidgetLayoutManager::SetOneBigLayout() +{ + MITK_INFO << "Set single 2D layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + mainSplit->addWidget(m_CurrentRenderWindowWidget); + m_CurrentRenderWindowWidget->show(); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ONE_BIG); + } +} + +void QmitkMultiWidgetLayoutManager::SetOnly2DHorizontalLayout() +{ + MITK_INFO << "Set only 2D layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + QList splitterSize; + auto all2DRenderWindowWidgets = m_MultiWidget->Get2DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all2DRenderWindowWidgets) + { + mainSplit->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ONLY_2D_HORIZONTAL); + } +} + +void QmitkMultiWidgetLayoutManager::SetOnly2DVerticalLayout() +{ + MITK_INFO << "Set only 2D layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(Qt::Vertical, m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + QList splitterSize; + auto all2DRenderWindowWidgets = m_MultiWidget->Get2DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all2DRenderWindowWidgets) + { + mainSplit->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ONLY_2D_VERTICAL); + } +} + +void QmitkMultiWidgetLayoutManager::SetOneTop3DBottomLayout() +{ + MITK_INFO << "Set one top and all 3D bottom layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(Qt::Vertical, m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + mainSplit->addWidget(m_CurrentRenderWindowWidget); + m_CurrentRenderWindowWidget->show(); + + auto subSplit3D = new QSplitter(mainSplit); + QList splitterSize; + auto all3DRenderWindowWidgets = m_MultiWidget->Get3DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all3DRenderWindowWidgets) + { + subSplit3D->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + subSplit3D->setSizes(splitterSize); + + // set size for main splitter + splitterSize.clear(); + splitterSize.push_back(1000); + splitterSize.push_back(1000); + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ONE_TOP_3D_BOTTOM); + } +} + +void QmitkMultiWidgetLayoutManager::SetOneLeft3DRightLayout() +{ + MITK_INFO << "Set one left and all 3D right layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + mainSplit->addWidget(m_CurrentRenderWindowWidget); + m_CurrentRenderWindowWidget->show(); + + auto subSplit3D = new QSplitter(Qt::Vertical, mainSplit); + QList splitterSize; + auto all3DRenderWindowWidgets = m_MultiWidget->Get3DRenderWindowWidgets(); + for (const auto& renderWindowWidget : all3DRenderWindowWidgets) + { + subSplit3D->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + subSplit3D->setSizes(splitterSize); + + // set size for main splitter + splitterSize.clear(); + splitterSize.push_back(1000); + splitterSize.push_back(1000); + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ONE_LEFT_3D_RIGHT); + } +} + +void QmitkMultiWidgetLayoutManager::SetAllHorizontalLayout() +{ + MITK_INFO << "Set default layout" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + QList splitterSize; + auto allRenderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : allRenderWindowWidgets) + { + if (nullptr != renderWindowWidget.second) + { + mainSplit->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + } + + // set size for main splitter + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ALL_HORIZONTAL); + } +} + +void QmitkMultiWidgetLayoutManager::SetAllVerticalLayout() +{ + MITK_INFO << "Set all vertical" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + delete m_MultiWidget->layout(); + + auto hBoxLayout = new QHBoxLayout(m_MultiWidget); + hBoxLayout->setContentsMargins(0, 0, 0, 0); + m_MultiWidget->setLayout(hBoxLayout); + hBoxLayout->setMargin(0); + + auto mainSplit = new QSplitter(Qt::Vertical, m_MultiWidget); + hBoxLayout->addWidget(mainSplit); + + QList splitterSize; + auto allRenderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : allRenderWindowWidgets) + { + mainSplit->addWidget(renderWindowWidget.second.get()); + renderWindowWidget.second->show(); + splitterSize.push_back(1000); + } + + // set size for splitter + mainSplit->setSizes(splitterSize); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::ALL_VERTICAL); + } +} + +void QmitkMultiWidgetLayoutManager::RemoveOneLayout() +{ + MITK_INFO << "Remove single render window" << std::endl; + + m_MultiWidget->ActivateMenuWidget(false); + + m_CurrentRenderWindowWidget->hide(); + + m_MultiWidget->ActivateMenuWidget(true); + + auto allRenderWindows = m_MultiWidget->GetRenderWindows(); + for (auto& renderWindow : allRenderWindows) + { + renderWindow->LayoutDesignListChanged(LayoutDesign::NONE); + } +} diff --git a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp index c79582fbdc..09e1d4775c 100644 --- a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp @@ -1,445 +1,257 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMxNMultiWidget.h" - -#include -#include -#include -#include - -// mitk core -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include "QmitkRenderWindowWidget.h" // qt #include QmitkMxNMultiWidget::QmitkMxNMultiWidget(QWidget* parent, - Qt::WindowFlags f/* = 0*/, - mitk::RenderingManager* renderingManager/* = nullptr*/, - mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, - const QString& multiWidgetName/* = "mxnmulti"*/) - : QWidget(parent, f) - , m_MxNMultiWidgetLayout(nullptr) - , m_MultiWidgetRows(0) - , m_MultiWidgetColumns(0) - , m_PlaneMode(0) - , m_RenderingManager(renderingManager) - , m_RenderingMode(renderingMode) - , m_MultiWidgetName(multiWidgetName) - , m_DisplayActionEventBroadcast(nullptr) - , m_DisplayActionEventHandler(nullptr) - , m_DataStorage(nullptr) + Qt::WindowFlags f/* = 0*/, + mitk::RenderingManager* renderingManager/* = nullptr*/, + mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, + const QString& multiWidgetName/* = "mxnmulti"*/) + : QmitkAbstractMultiWidget(parent, f, renderingManager, renderingMode, multiWidgetName) + , m_CrosshairVisibility(false) { - InitializeGUI(); - InitializeDisplayActionEventHandling(); - resize(QSize(364, 477).expandedTo(minimumSizeHint())); + // nothing here } -void QmitkMxNMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) +void QmitkMxNMultiWidget::InitializeMultiWidget() { - if (dataStorage == m_DataStorage) - { - return; - } + SetLayout(1, 1); - m_DataStorage = dataStorage; - // set new data storage for the render window widgets - for (const auto& renderWindowWidget : m_RenderWindowWidgets) - { - renderWindowWidget.second->SetDataStorage(m_DataStorage); - } + ActivateMenuWidget(true); } -void QmitkMxNMultiWidget::InitializeRenderWindowWidgets() +void QmitkMxNMultiWidget::MultiWidgetOpened() { - m_MultiWidgetRows = 1; - m_MultiWidgetColumns = 1; - CreateRenderWindowWidget(); - InitializeGUI(); -} - -void QmitkMxNMultiWidget::ResetLayout(int row, int column) -{ - m_MultiWidgetRows = row; - m_MultiWidgetColumns = column; - - int requiredRenderWindowWidgets = m_MultiWidgetRows * m_MultiWidgetColumns; - int existingRenderWindowWidgets = m_RenderWindowWidgets.size(); - - int difference = requiredRenderWindowWidgets - existingRenderWindowWidgets; - while(0 < difference) - { - // more render window widgets needed - CreateRenderWindowWidget(); - --difference; - } - while(0 > difference) - { - // less render window widgets needed - DestroyRenderWindowWidget(); - ++difference; - } - - InitializeGUI(); + SetCrosshairVisibility(true); } -void QmitkMxNMultiWidget::Synchronize(bool synchronized) +void QmitkMxNMultiWidget::MultiWidgetClosed() { - auto allObserverTags = m_DisplayActionEventHandler->GetAllObserverTags(); - for (auto observerTag : allObserverTags) - { - m_DisplayActionEventHandler->DisconnectObserver(observerTag); - } - - if (synchronized) - { - mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); - - actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); - - actionFunction = mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); - - actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); - } - else - { - mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveSenderCameraAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); - - actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); - - actionFunction = mitk::DisplayActionEventFunctions::ZoomSenderCameraAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); - - actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); - } - - // use the standard 'set level window' action for both modes - mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::SetLevelWindowAction(); - m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetLevelWindowEvent(nullptr, mitk::ScalarType(), mitk::ScalarType()), actionFunction); + SetCrosshairVisibility(false); } -void QmitkMxNMultiWidget::SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) +QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const QString& widgetName) const { - auto interactionSchemeSwitcher = mitk::InteractionSchemeSwitcher::New(); - auto interactionEventHandler = GetInteractionEventHandler(); - try + if ("axial" == widgetName || "sagittal" == widgetName || "coronal" == widgetName || "3d" == widgetName) { - interactionSchemeSwitcher->SetInteractionScheme(interactionEventHandler, scheme); + return GetActiveRenderWindowWidget()->GetRenderWindow(); } - catch (const mitk::Exception&) - { - return; - } -} -QmitkMxNMultiWidget::RenderWindowWidgetMap QmitkMxNMultiWidget::GetRenderWindowWidgets() const -{ - return m_RenderWindowWidgets; + return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } -QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetRenderWindowWidget(int row, int column) const +QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const mitk::BaseRenderer::ViewDirection& /*viewDirection*/) const { - return GetRenderWindowWidget(GetNameFromIndex(row, column)); + // currently no mapping between view directions and render windows + // simply return the currently active render window + return GetActiveRenderWindowWidget()->GetRenderWindow(); } -QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetRenderWindowWidget(const QString& widgetName) const +void QmitkMxNMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) { - RenderWindowWidgetMap::const_iterator it = m_RenderWindowWidgets.find(widgetName); - if (it != m_RenderWindowWidgets.end()) + auto currentActiveRenderWindowWidget = GetActiveRenderWindowWidget(); + if (currentActiveRenderWindowWidget == activeRenderWindowWidget) { - return it->second; + return; } - return nullptr; -} - -QmitkMxNMultiWidget::RenderWindowHash QmitkMxNMultiWidget::GetRenderWindows() const -{ - RenderWindowHash result; - // create QHash on demand - auto renderWindowWidgets = GetRenderWindowWidgets(); - for (const auto& renderWindowWidget : renderWindowWidgets) + // reset the decoration color of the previously active render window widget + if (nullptr != currentActiveRenderWindowWidget) { - result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); - } - - return result; -} + auto decorationColor = currentActiveRenderWindowWidget->GetDecorationColor(); + QColor hexColor(decorationColor[0] * 255, decorationColor[1] * 255, decorationColor[2] * 255); + currentActiveRenderWindowWidget->setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); -QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(int row, int column) const -{ - return GetRenderWindow(GetNameFromIndex(row, column)); -} + } -QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const QString& widgetName) const -{ - RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); - if (nullptr != renderWindowWidget) + // set the new decoration color of the currently active render window widget + if (nullptr != activeRenderWindowWidget) { - return renderWindowWidget->GetRenderWindow(); + activeRenderWindowWidget->setStyleSheet("border: 2px solid #FF6464"); } - return nullptr; -} - -void QmitkMxNMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) -{ - m_ActiveRenderWindowWidget = activeRenderWindowWidget; -} - -QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetActiveRenderWindowWidget() const -{ - return m_ActiveRenderWindowWidget; + QmitkAbstractMultiWidget::SetActiveRenderWindowWidget(activeRenderWindowWidget); } -QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetFirstRenderWindowWidget() const +void QmitkMxNMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) { - if (!m_RenderWindowWidgets.empty()) + RenderWindowWidgetPointer renderWindowWidget; + if (widgetName.isNull()) { - return m_RenderWindowWidgets.begin()->second; + renderWindowWidget = GetActiveRenderWindowWidget(); } else { - return nullptr; + renderWindowWidget = GetRenderWindowWidget(widgetName); } -} -QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetLastRenderWindowWidget() const -{ - if (!m_RenderWindowWidgets.empty()) - { - return m_RenderWindowWidgets.rbegin()->second; - } - else + if (nullptr != renderWindowWidget) { - return nullptr; + renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); + renderWindowWidget->RequestUpdate(); + return; } -} -unsigned int QmitkMxNMultiWidget::GetNumberOfRenderWindowWidgets() const -{ - return m_RenderWindowWidgets.size(); + MITK_ERROR << "Position can not be set for an unknown render window widget."; } -void QmitkMxNMultiWidget::RequestUpdate(const QString& widgetName) +const mitk::Point3D QmitkMxNMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { - RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); - if (nullptr != renderWindowWidget) - { - return renderWindowWidget->RequestUpdate(); - } + // see T26208 + return mitk::Point3D(); } -void QmitkMxNMultiWidget::RequestUpdateAll() +void QmitkMxNMultiWidget::SetCrosshairVisibility(bool activate) { - for (const auto& renderWindowWidget : m_RenderWindowWidgets) + auto renderWindowWidgets = GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) { - renderWindowWidget.second->RequestUpdate(); + renderWindowWidget.second->ActivateCrosshair(activate); } -} -void QmitkMxNMultiWidget::ForceImmediateUpdate(const QString& widgetName) -{ - RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); - if (nullptr != renderWindowWidget) - { - renderWindowWidget->ForceImmediateUpdate(); - } + m_CrosshairVisibility = activate; } -void QmitkMxNMultiWidget::ForceImmediateUpdateAll() +void QmitkMxNMultiWidget::ResetCrosshair() { - for (const auto& renderWindowWidget : m_RenderWindowWidgets) + auto dataStorage = GetDataStorage(); + if (nullptr == dataStorage) { - renderWindowWidget.second->ForceImmediateUpdate(); + return; } -} -void QmitkMxNMultiWidget::ActivateAllCrosshairs(bool activate) -{ - for (const auto& renderWindowWidget : m_RenderWindowWidgets) + auto renderingManager = GetRenderingManager(); + if (nullptr == renderingManager) { - renderWindowWidget.second->ActivateCrosshair(activate); + return; } -} -const mitk::Point3D QmitkMxNMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const -{ - // see T26208 - return mitk::Point3D(); + renderingManager->InitializeViewsByBoundingObjects(dataStorage); + + SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } -////////////////////////////////////////////////////////////////////////// -// PUBLIC SLOTS -////////////////////////////////////////////////////////////////////////// -void QmitkMxNMultiWidget::SetSelectedPosition(const QString& widgetName, const mitk::Point3D& newPosition) +void QmitkMxNMultiWidget::SetWidgetPlaneMode(int userMode) { - RenderWindowWidgetPointer renderWindowWidget; - if (widgetName.isNull()) - { - renderWindowWidget = GetActiveRenderWindowWidget(); - } - else - { - renderWindowWidget = GetRenderWindowWidget(widgetName); - } + MITK_DEBUG << "Changing crosshair mode to " << userMode; - if (nullptr != renderWindowWidget) + switch (userMode) { - renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); - renderWindowWidget->RequestUpdate(); - return; + case 0: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); + break; + case 1: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); + break; + case 2: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); + break; + case 3: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); + break; } - - MITK_ERROR << "Position can not be set for an unknown render window widget."; } ////////////////////////////////////////////////////////////////////////// +// PUBLIC SLOTS // MOUSE EVENTS ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } -void QmitkMxNMultiWidget::mousePressEvent(QMouseEvent* /*e*/) +void QmitkMxNMultiWidget::mousePressEvent(QMouseEvent* e) { + if (QEvent::MouseButtonPress != e->type()) + { + return; + } + + auto renderWindowWidget = dynamic_cast(this->sender()); + if (nullptr == renderWindowWidget) + { + return; + } + + auto renderWindowWidgetPointer = GetRenderWindowWidget(renderWindowWidget->GetWidgetName()); + SetActiveRenderWindowWidget(renderWindowWidgetPointer); } void QmitkMxNMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the overlays as the MultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// -void QmitkMxNMultiWidget::InitializeGUI() +void QmitkMxNMultiWidget::SetLayoutImpl() { - delete m_MxNMultiWidgetLayout; - m_MxNMultiWidgetLayout = new QGridLayout(this); - m_MxNMultiWidgetLayout->setContentsMargins(0, 0, 0, 0); - setLayout(m_MxNMultiWidgetLayout); - - FillMultiWidgetLayout(); -} - -void QmitkMxNMultiWidget::InitializeDisplayActionEventHandling() -{ - m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); - m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); - m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigMITK.xml"); - - m_DisplayActionEventHandler = std::make_unique(); - m_DisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); - - Synchronize(true); -} - -void QmitkMxNMultiWidget::CreateRenderWindowWidget() -{ - // create the render window widget and connect signals / slots - QString renderWindowWidgetName = GetNameFromIndex(m_RenderWindowWidgets.size()); - RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, m_DataStorage); - renderWindowWidget->SetCornerAnnotationText(renderWindowWidgetName.toStdString()); - - // store the newly created render window widget with the UID - m_RenderWindowWidgets.insert(std::make_pair(renderWindowWidgetName, renderWindowWidget)); -} + int requiredRenderWindowWidgets = GetRowCount() * GetColumnCount(); + int existingRenderWindowWidgets = GetRenderWindowWidgets().size(); -void QmitkMxNMultiWidget::DestroyRenderWindowWidget() -{ - auto iterator = m_RenderWindowWidgets.find(GetNameFromIndex(m_RenderWindowWidgets.size() - 1)); - if (iterator == m_RenderWindowWidgets.end()) + int difference = requiredRenderWindowWidgets - existingRenderWindowWidgets; + while (0 < difference) { - return; + // more render window widgets needed + CreateRenderWindowWidget(); + --difference; } - // disconnect each signal of this render window widget - RenderWindowWidgetPointer renderWindowWidgetToRemove = iterator->second; - disconnect(renderWindowWidgetToRemove.get(), nullptr, nullptr, nullptr); - - // erase the render window from the map - m_RenderWindowWidgets.erase(iterator); -} - -void QmitkMxNMultiWidget::FillMultiWidgetLayout() -{ - for (int row = 0; row < m_MultiWidgetRows; ++row) + while (0 > difference) { - for (int column = 0; column < m_MultiWidgetColumns; ++column) - { - RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(row, column); - if (nullptr != renderWindowWidget) - { - m_MxNMultiWidgetLayout->addWidget(renderWindowWidget.get(), row, column); - SetActiveRenderWindowWidget(renderWindowWidget); - } - } + // less render window widgets needed + RemoveRenderWindowWidget(); + ++difference; } -} -QString QmitkMxNMultiWidget::GetNameFromIndex(int row, int column) const -{ - if (0 <= row && m_MultiWidgetRows > row && 0 <= column && m_MultiWidgetColumns > column) + auto firstRenderWindowWidget = GetFirstRenderWindowWidget(); + if (nullptr != firstRenderWindowWidget) { - return GetNameFromIndex(row * m_MultiWidgetColumns + column); + SetActiveRenderWindowWidget(firstRenderWindowWidget); } - return QString(); + GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); } -QString QmitkMxNMultiWidget::GetNameFromIndex(size_t index) const +void QmitkMxNMultiWidget::CreateRenderWindowWidget() { - if (index <= m_RenderWindowWidgets.size()) - { - return m_MultiWidgetName + ".widget" + QString::number(index); - } + // create the render window widget and connect signal / slot + QString renderWindowWidgetName = GetNameFromIndex(GetNumberOfRenderWindowWidgets()); + RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + renderWindowWidget->SetCornerAnnotationText(renderWindowWidgetName.toStdString()); + + connect(renderWindowWidget.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkMxNMultiWidget::mousePressEvent); + + AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget); - return QString(); + auto renderWindow = renderWindowWidget->GetRenderWindow(); + auto layoutManager = GetMultiWidgetLayoutManager(); + connect(renderWindow, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); + connect(renderWindow, &QmitkRenderWindow::ResetView, this, &QmitkMxNMultiWidget::ResetCrosshair); + connect(renderWindow, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkMxNMultiWidget::SetCrosshairVisibility); + connect(renderWindow, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkMxNMultiWidget::SetWidgetPlaneMode); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindow.cpp b/Modules/QtWidgets/src/QmitkRenderWindow.cpp index 8edf678a5d..becf3d7a2c 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindow.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindow.cpp @@ -1,506 +1,506 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindow.h" #include "mitkInteractionKeyEvent.h" #include "mitkInternalEvent.h" #include "mitkMouseDoubleClickEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMousePressEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkMouseWheelEvent.h" #include #include #include #include #include #include #include #include #include #include #include "QmitkMimeTypes.h" #include "QmitkRenderWindowMenu.h" QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *, mitk::RenderingManager *renderingManager, mitk::BaseRenderer::RenderingMode::Type renderingMode) - : QVTKOpenGLWidget(parent), - m_ResendQtEvents(true), - m_MenuWidget(nullptr), - m_MenuWidgetActivated(false), - m_LayoutIndex(0) + : QVTKOpenGLWidget(parent) + , m_ResendQtEvents(true) + , m_MenuWidget(nullptr) + , m_MenuWidgetActivated(false) + , m_LayoutIndex(QmitkRenderWindowMenu::LayoutIndex::AXIAL) { m_InternalRenderWindow = vtkSmartPointer::New(); m_InternalRenderWindow->SetMultiSamples(0); m_InternalRenderWindow->SetAlphaBitPlanes(0); - this->SetRenderWindow(m_InternalRenderWindow); + SetRenderWindow(m_InternalRenderWindow); - this->Initialize(renderingManager, name.toStdString().c_str(), renderingMode); + Initialize(renderingManager, name.toStdString().c_str(), renderingMode); - this->setFocusPolicy(Qt::StrongFocus); - this->setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); + setMouseTracking(true); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - this->setSizePolicy(sizePolicy); + setSizePolicy(sizePolicy); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } -void QmitkRenderWindow::SetLayoutIndex(unsigned int layoutIndex) +void QmitkRenderWindow::SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex) { m_LayoutIndex = layoutIndex; - if (m_MenuWidget) + if (nullptr != m_MenuWidget) + { m_MenuWidget->SetLayoutIndex(layoutIndex); + } } -unsigned int QmitkRenderWindow::GetLayoutIndex() +QmitkRenderWindowMenu::LayoutIndex QmitkRenderWindow::GetLayoutIndex() { - if (m_MenuWidget) + if (nullptr != m_MenuWidget) + { return m_MenuWidget->GetLayoutIndex(); + } else - return 0; + { + return QmitkRenderWindowMenu::LayoutIndex::AXIAL; + } } -void QmitkRenderWindow::LayoutDesignListChanged(int layoutDesignIndex) +void QmitkRenderWindow::LayoutDesignListChanged(QmitkRenderWindowMenu::LayoutDesign layoutDesign) { - if (m_MenuWidget) - m_MenuWidget->UpdateLayoutDesignList(layoutDesignIndex); + if (nullptr != m_MenuWidget) + { + m_MenuWidget->UpdateLayoutDesignList(layoutDesign); + } +} + +void QmitkRenderWindow::ActivateMenuWidget(bool state) +{ + if (nullptr == m_MenuWidget) + { + m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer); + m_MenuWidget->SetLayoutIndex(m_LayoutIndex); + } + + m_MenuWidgetActivated = state; + + if (m_MenuWidgetActivated) + { + connect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); + connect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); + connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); + connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); + } + else + { + disconnect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); + disconnect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); + disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); + disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); + + m_MenuWidget->hide(); + } +} + +void QmitkRenderWindow::moveEvent(QMoveEvent *event) +{ + QVTKOpenGLWidget::moveEvent(event); + + // after a move the overlays need to be positioned + emit moved(); +} + +void QmitkRenderWindow::showEvent(QShowEvent *event) +{ + QVTKOpenGLWidget::showEvent(event); + + // this singleshot is necessary to have the overlays positioned correctly after initial show + // simple call of moved() is no use here!! + QTimer::singleShot(0, this, SIGNAL(moved())); } void QmitkRenderWindow::mousePressEvent(QMouseEvent *me) { // Get mouse position in vtk display coordinate system. me contains qt display infos... mitk::Point2D displayPos = GetMousePosition(me); mitk::MousePressEvent::Pointer mPressEvent = mitk::MousePressEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { QVTKOpenGLWidget::mousePressEvent(me); } if (m_ResendQtEvents) + { me->ignore(); + } } void QmitkRenderWindow::mouseDoubleClickEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); mitk::MouseDoubleClickEvent::Pointer mPressEvent = mitk::MouseDoubleClickEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { QVTKOpenGLWidget::mousePressEvent(me); } if (m_ResendQtEvents) + { me->ignore(); + } } void QmitkRenderWindow::mouseReleaseEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); mitk::MouseReleaseEvent::Pointer mReleaseEvent = mitk::MouseReleaseEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mReleaseEvent.GetPointer())) { QVTKOpenGLWidget::mouseReleaseEvent(me); } if (m_ResendQtEvents) + { me->ignore(); + } } void QmitkRenderWindow::mouseMoveEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); - this->AdjustRenderWindowMenuVisibility(me->pos()); + AdjustRenderWindowMenuVisibility(me->pos()); mitk::MouseMoveEvent::Pointer mMoveEvent = mitk::MouseMoveEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me)); if (!this->HandleEvent(mMoveEvent.GetPointer())) { QVTKOpenGLWidget::mouseMoveEvent(me); } } void QmitkRenderWindow::wheelEvent(QWheelEvent *we) { mitk::Point2D displayPos = GetMousePosition(we); mitk::MouseWheelEvent::Pointer mWheelEvent = mitk::MouseWheelEvent::New(m_Renderer, displayPos, GetButtonState(we), GetModifiers(we), GetDelta(we)); if (!this->HandleEvent(mWheelEvent.GetPointer())) { QVTKOpenGLWidget::wheelEvent(we); } if (m_ResendQtEvents) + { we->ignore(); + } } void QmitkRenderWindow::keyPressEvent(QKeyEvent *ke) { mitk::InteractionEvent::ModifierKeys modifiers = GetModifiers(ke); std::string key = GetKeyLetter(ke); mitk::InteractionKeyEvent::Pointer keyEvent = mitk::InteractionKeyEvent::New(m_Renderer, key, modifiers); if (!this->HandleEvent(keyEvent.GetPointer())) { QVTKOpenGLWidget::keyPressEvent(ke); } if (m_ResendQtEvents) + { ke->ignore(); + } } void QmitkRenderWindow::enterEvent(QEvent *e) { // TODO implement new event QVTKOpenGLWidget::enterEvent(e); } -void QmitkRenderWindow::DeferredHideMenu() -{ - MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; - - if (m_MenuWidget) - m_MenuWidget->HideMenu(); -} - void QmitkRenderWindow::leaveEvent(QEvent *e) { mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, nullptr, "LeaveRenderWindow"); this->HandleEvent(internalEvent.GetPointer()); - if (m_MenuWidget) + if (nullptr != m_MenuWidget) + { m_MenuWidget->smoothHide(); + } QVTKOpenGLWidget::leaveEvent(e); } -//----------------------------------------------------------------------------- void QmitkRenderWindow::resizeGL(int w, int h) { this->GetRenderer()->GetRenderingManager()->ForceImmediateUpdate(GetRenderWindow()); QVTKOpenGLWidget::resizeGL(w, h); } -void QmitkRenderWindow::moveEvent(QMoveEvent *event) -{ - QVTKOpenGLWidget::moveEvent(event); - - // after a move the overlays need to be positioned - emit moved(); -} - -void QmitkRenderWindow::showEvent(QShowEvent *event) +void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) { - QVTKOpenGLWidget::showEvent(event); - - // this singleshot is necessary to have the overlays positioned correctly after initial show - // simple call of moved() is no use here!! - QTimer::singleShot(0, this, SIGNAL(moved())); + if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) + { + event->accept(); + } } -void QmitkRenderWindow::ActivateMenuWidget(bool state, QmitkStdMultiWidget *stdMultiWidget) +void QmitkRenderWindow::dropEvent(QDropEvent *event) { - m_MenuWidgetActivated = state; - - if (!m_MenuWidgetActivated && m_MenuWidget) - { - // disconnect Signal/Slot Connection - disconnect(m_MenuWidget, SIGNAL(SignalChangeLayoutDesign(int)), this, SLOT(OnChangeLayoutDesign(int))); - disconnect(m_MenuWidget, SIGNAL(ResetView()), this, SIGNAL(ResetView())); - disconnect(m_MenuWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SIGNAL(ChangeCrosshairRotationMode(int))); - - delete m_MenuWidget; - m_MenuWidget = nullptr; - } - else if (m_MenuWidgetActivated && !m_MenuWidget) + QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); + if (!dataNodeList.empty()) { - // create render window MenuBar for split, close Window or set new setting. - m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer, stdMultiWidget); - m_MenuWidget->SetLayoutIndex(m_LayoutIndex); - - // create Signal/Slot Connection - connect(m_MenuWidget, SIGNAL(SignalChangeLayoutDesign(int)), this, SLOT(OnChangeLayoutDesign(int))); - connect(m_MenuWidget, SIGNAL(ResetView()), this, SIGNAL(ResetView())); - connect(m_MenuWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SIGNAL(ChangeCrosshairRotationMode(int))); + emit NodesDropped(this, dataNodeList.toVector().toStdVector()); } } void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint & /*pos*/) { - if (m_MenuWidget) + if (nullptr != m_MenuWidget) { m_MenuWidget->ShowMenu(); m_MenuWidget->MoveWidgetToCorrectPos(1.0f); } } -void QmitkRenderWindow::HideRenderWindowMenu() -{ - // DEPRECATED METHOD -} - -void QmitkRenderWindow::OnChangeLayoutDesign(int layoutDesignIndex) -{ - emit SignalLayoutDesignChanged(layoutDesignIndex); -} - -void QmitkRenderWindow::OnWidgetPlaneModeChanged(int mode) -{ - if (m_MenuWidget) - m_MenuWidget->NotifyNewWidgetPlanesMode(mode); -} - -void QmitkRenderWindow::FullScreenMode(bool state) +void QmitkRenderWindow::DeferredHideMenu() { - if (m_MenuWidget) - m_MenuWidget->ChangeFullScreenMode(state); -} + MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; -void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) -{ - if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) + if (nullptr != m_MenuWidget) { - event->accept(); - } -} - -void QmitkRenderWindow::dropEvent(QDropEvent *event) -{ - QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); - if (!dataNodeList.empty()) - { - emit NodesDropped(this, dataNodeList.toVector().toStdVector()); + m_MenuWidget->HideMenu(); } } mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent *me) const { mitk::Point2D point; point[0] = me->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - me->y(); return point; } mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent *we) const { mitk::Point2D point; point[0] = we->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - we->y(); return point; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons eventButton; switch (me->button()) { - case Qt::LeftButton: - eventButton = mitk::InteractionEvent::LeftMouseButton; - break; - case Qt::RightButton: - eventButton = mitk::InteractionEvent::RightMouseButton; - break; - case Qt::MidButton: - eventButton = mitk::InteractionEvent::MiddleMouseButton; - break; - default: - eventButton = mitk::InteractionEvent::NoButton; - break; + case Qt::LeftButton: + eventButton = mitk::InteractionEvent::LeftMouseButton; + break; + case Qt::RightButton: + eventButton = mitk::InteractionEvent::RightMouseButton; + break; + case Qt::MidButton: + eventButton = mitk::InteractionEvent::MiddleMouseButton; + break; + default: + eventButton = mitk::InteractionEvent::NoButton; + break; } return eventButton; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent *me) const { mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::InteractionEvent::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::InteractionEvent::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::InteractionEvent::ShiftKey; } return modifiers; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent *we) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const { // Converting Qt Key Event to string element. std::string key = ""; int tkey = ke->key(); if (tkey < 128) { // standard ascii letter key = (char)toupper(tkey); } else { // special keys switch (tkey) { - case Qt::Key_Return: - key = mitk::InteractionEvent::KeyReturn; - break; - case Qt::Key_Enter: - key = mitk::InteractionEvent::KeyEnter; - break; - case Qt::Key_Escape: - key = mitk::InteractionEvent::KeyEsc; - break; - case Qt::Key_Delete: - key = mitk::InteractionEvent::KeyDelete; - break; - case Qt::Key_Up: - key = mitk::InteractionEvent::KeyArrowUp; - break; - case Qt::Key_Down: - key = mitk::InteractionEvent::KeyArrowDown; - break; - case Qt::Key_Left: - key = mitk::InteractionEvent::KeyArrowLeft; - break; - case Qt::Key_Right: - key = mitk::InteractionEvent::KeyArrowRight; - break; - - case Qt::Key_F1: - key = mitk::InteractionEvent::KeyF1; - break; - case Qt::Key_F2: - key = mitk::InteractionEvent::KeyF2; - break; - case Qt::Key_F3: - key = mitk::InteractionEvent::KeyF3; - break; - case Qt::Key_F4: - key = mitk::InteractionEvent::KeyF4; - break; - case Qt::Key_F5: - key = mitk::InteractionEvent::KeyF5; - break; - case Qt::Key_F6: - key = mitk::InteractionEvent::KeyF6; - break; - case Qt::Key_F7: - key = mitk::InteractionEvent::KeyF7; - break; - case Qt::Key_F8: - key = mitk::InteractionEvent::KeyF8; - break; - case Qt::Key_F9: - key = mitk::InteractionEvent::KeyF9; - break; - case Qt::Key_F10: - key = mitk::InteractionEvent::KeyF10; - break; - case Qt::Key_F11: - key = mitk::InteractionEvent::KeyF11; - break; - case Qt::Key_F12: - key = mitk::InteractionEvent::KeyF12; - break; - - case Qt::Key_End: - key = mitk::InteractionEvent::KeyEnd; - break; - case Qt::Key_Home: - key = mitk::InteractionEvent::KeyPos1; - break; - case Qt::Key_Insert: - key = mitk::InteractionEvent::KeyInsert; - break; - case Qt::Key_PageDown: - key = mitk::InteractionEvent::KeyPageDown; - break; - case Qt::Key_PageUp: - key = mitk::InteractionEvent::KeyPageUp; - break; - case Qt::Key_Space: - key = mitk::InteractionEvent::KeySpace; - break; + case Qt::Key_Return: + key = mitk::InteractionEvent::KeyReturn; + break; + case Qt::Key_Enter: + key = mitk::InteractionEvent::KeyEnter; + break; + case Qt::Key_Escape: + key = mitk::InteractionEvent::KeyEsc; + break; + case Qt::Key_Delete: + key = mitk::InteractionEvent::KeyDelete; + break; + case Qt::Key_Up: + key = mitk::InteractionEvent::KeyArrowUp; + break; + case Qt::Key_Down: + key = mitk::InteractionEvent::KeyArrowDown; + break; + case Qt::Key_Left: + key = mitk::InteractionEvent::KeyArrowLeft; + break; + case Qt::Key_Right: + key = mitk::InteractionEvent::KeyArrowRight; + break; + + case Qt::Key_F1: + key = mitk::InteractionEvent::KeyF1; + break; + case Qt::Key_F2: + key = mitk::InteractionEvent::KeyF2; + break; + case Qt::Key_F3: + key = mitk::InteractionEvent::KeyF3; + break; + case Qt::Key_F4: + key = mitk::InteractionEvent::KeyF4; + break; + case Qt::Key_F5: + key = mitk::InteractionEvent::KeyF5; + break; + case Qt::Key_F6: + key = mitk::InteractionEvent::KeyF6; + break; + case Qt::Key_F7: + key = mitk::InteractionEvent::KeyF7; + break; + case Qt::Key_F8: + key = mitk::InteractionEvent::KeyF8; + break; + case Qt::Key_F9: + key = mitk::InteractionEvent::KeyF9; + break; + case Qt::Key_F10: + key = mitk::InteractionEvent::KeyF10; + break; + case Qt::Key_F11: + key = mitk::InteractionEvent::KeyF11; + break; + case Qt::Key_F12: + key = mitk::InteractionEvent::KeyF12; + break; + + case Qt::Key_End: + key = mitk::InteractionEvent::KeyEnd; + break; + case Qt::Key_Home: + key = mitk::InteractionEvent::KeyPos1; + break; + case Qt::Key_Insert: + key = mitk::InteractionEvent::KeyInsert; + break; + case Qt::Key_PageDown: + key = mitk::InteractionEvent::KeyPageDown; + break; + case Qt::Key_PageUp: + key = mitk::InteractionEvent::KeyPageUp; + break; + case Qt::Key_Space: + key = mitk::InteractionEvent::KeySpace; + break; } } return key; } int QmitkRenderWindow::GetDelta(QWheelEvent *we) const { return we->delta(); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp index 00177a56b3..c48501374b 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp @@ -1,1026 +1,652 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindowMenu.h" +// mitk core #include "mitkProperties.h" #include "mitkResliceMethodProperty.h" +// qt #include #include #include #include #include -#include #include -#include #include #include #include -#include - -#include "QmitkStdMultiWidget.h" - //#include"iconClose.xpm" #include "iconCrosshairMode.xpm" #include "iconFullScreen.xpm" //#include"iconHoriSplit.xpm" #include "iconSettings.xpm" //#include"iconVertiSplit.xpm" #include "iconLeaveFullScreen.xpm" +// c++ #include unsigned int QmitkRenderWindowMenu::m_DefaultThickMode(1); #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU -QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget *parent, - Qt::WindowFlags, - mitk::BaseRenderer *b, - QmitkStdMultiWidget *mw) - : QWidget(nullptr, Qt::Tool | Qt::FramelessWindowHint), +QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget* parent, + Qt::WindowFlags flags, + mitk::BaseRenderer* baseRenderer) + : QWidget(nullptr, Qt::Tool | Qt::FramelessWindowHint) #else -QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget *parent, - Qt::WindowFlags f, - mitk::BaseRenderer *b, - QmitkStdMultiWidget *mw) - : QWidget(parent, f), +QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget* parent, + Qt::WindowFlags flags, + mitk::BaseRenderer* baseRenderer) + : QWidget(parent, flags) #endif - m_Settings(nullptr), - m_CrosshairMenu(nullptr), - m_Layout(0), - m_LayoutDesign(0), - m_OldLayoutDesign(0), - m_FullScreenMode(false), - m_Entered(false), - m_Renderer(b), - m_MultiWidget(mw), - m_Parent(parent) -{ - // Create Menu Widget - this->CreateMenuWidget(); - this->setMinimumWidth(61); // DIRTY.. If you add or remove a button, you need to change the size. - this->setMaximumWidth(61); - this->setAutoFillBackground(true); + , m_LayoutActionsMenu(nullptr) + , m_CrosshairMenu(nullptr) + , m_FullScreenMode(false) + , m_Renderer(baseRenderer) + , m_Parent(parent) + , m_CrosshairRotationMode(0) + , m_CrosshairVisibility(false) + , m_Layout(LayoutIndex::AXIAL) + , m_LayoutDesign(LayoutDesign::DEFAULT) + , m_OldLayoutDesign(LayoutDesign::DEFAULT) +{ + CreateMenuWidget(); + setMinimumWidth(61); // DIRTY.. If you add or remove a button, you need to change the size. + setMaximumWidth(61); + setAutoFillBackground(true); // Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows // for macOS see bug 3192 // for Windows see bug 12130 //... so macOS and Windows must be treated differently: #if defined(Q_OS_MAC) this->show(); this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif - // this->setAttribute( Qt::WA_NoSystemBackground ); - // this->setBackgroundRole( QPalette::Dark ); - // this->update(); - - // SetOpacity -- its just posible if the widget is a window. - // Windows indicates that the widget is a window, usually with a window system frame and a title bar, - // irrespective of whether the widget has a parent or not. - /* - this->setWindowFlags( Qt::Window | Qt::FramelessWindowHint); - */ - // this->setAttribute(Qt::WA_TranslucentBackground); - // this->setWindowOpacity(0.75); - - currentCrosshairRotationMode = 0; - - // for autorotating - m_AutoRotationTimer.setInterval(75); - connect(&m_AutoRotationTimer, SIGNAL(timeout()), this, SLOT(AutoRotateNextStep())); - m_HideTimer.setSingleShot(true); - connect(&m_HideTimer, SIGNAL(timeout()), this, SLOT(DeferredHideMenu())); - connect(m_Parent, SIGNAL(destroyed()), this, SLOT(deleteLater())); + m_AutoRotationTimer = new QTimer(this); + m_AutoRotationTimer->setInterval(75); + + m_HideTimer = new QTimer(this); + m_HideTimer->setSingleShot(true); + + connect(m_AutoRotationTimer, &QTimer::timeout, this, &QmitkRenderWindowMenu::AutoRotateNextStep); + connect(m_HideTimer, &QTimer::timeout, this, &QmitkRenderWindowMenu::DeferredHideMenu); + connect(m_Parent, &QObject::destroyed, this, &QmitkRenderWindowMenu::deleteLater); } QmitkRenderWindowMenu::~QmitkRenderWindowMenu() { - if (m_AutoRotationTimer.isActive()) - m_AutoRotationTimer.stop(); + if (m_AutoRotationTimer->isActive()) + { + m_AutoRotationTimer->stop(); + } } -void QmitkRenderWindowMenu::CreateMenuWidget() +void QmitkRenderWindowMenu::SetLayoutIndex(LayoutIndex layoutIndex) { - QHBoxLayout *layout = new QHBoxLayout(this); - layout->setAlignment(Qt::AlignRight); - layout->setContentsMargins(1, 1, 1, 1); - - QSize size(13, 13); + m_Layout = layoutIndex; +} - m_CrosshairMenu = new QMenu(this); - connect(m_CrosshairMenu, SIGNAL(aboutToShow()), this, SLOT(OnCrossHairMenuAboutToShow())); +void QmitkRenderWindowMenu::UpdateLayoutDesignList(LayoutDesign layoutDesign) +{ + m_LayoutDesign = layoutDesign; - // button for changing rotation mode - m_CrosshairModeButton = new QToolButton(this); - m_CrosshairModeButton->setMaximumSize(15, 15); - m_CrosshairModeButton->setIconSize(size); - m_CrosshairModeButton->setMenu(m_CrosshairMenu); - m_CrosshairModeButton->setIcon(QIcon(QPixmap(iconCrosshairMode_xpm))); - m_CrosshairModeButton->setPopupMode(QToolButton::InstantPopup); - m_CrosshairModeButton->setStyleSheet("QToolButton::menu-indicator { image: none; }"); - m_CrosshairModeButton->setAutoRaise(true); - layout->addWidget(m_CrosshairModeButton); + if (nullptr == m_LayoutActionsMenu) + { + CreateSettingsWidget(); + } - // fullScreenButton - m_FullScreenButton = new QToolButton(this); - m_FullScreenButton->setMaximumSize(15, 15); - m_FullScreenButton->setIconSize(size); - m_FullScreenButton->setIcon(QIcon(QPixmap(iconFullScreen_xpm))); - m_FullScreenButton->setAutoRaise(true); - layout->addWidget(m_FullScreenButton); + m_DefaultLayoutAction->setEnabled(true); + m_All2DTop3DBottomLayoutAction->setEnabled(true); + m_All2DLeft3DRightLayoutAction->setEnabled(true); + m_OneBigLayoutAction->setEnabled(true); + m_Only2DHorizontalLayoutAction->setEnabled(true); + m_Only2DVerticalLayoutAction->setEnabled(true); + m_OneTop3DBottomLayoutAction->setEnabled(true); + m_OneLeft3DRightLayoutAction->setEnabled(true); + m_AllHorizontalLayoutAction->setEnabled(true); + m_AllVerticalLayoutAction->setEnabled(true); + m_RemoveOneLayoutAction->setEnabled(true); - // settingsButton - m_SettingsButton = new QToolButton(this); - m_SettingsButton->setMaximumSize(15, 15); - m_SettingsButton->setIconSize(size); - m_SettingsButton->setIcon(QIcon(QPixmap(iconSettings_xpm))); - m_SettingsButton->setAutoRaise(true); - layout->addWidget(m_SettingsButton); - - // Create Connections -- coming soon? - connect(m_FullScreenButton, SIGNAL(clicked(bool)), this, SLOT(OnFullScreenButton(bool))); - connect(m_SettingsButton, SIGNAL(clicked(bool)), this, SLOT(OnSettingsButton(bool))); + switch (m_LayoutDesign) + { + case LayoutDesign::DEFAULT: + { + m_DefaultLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ALL_2D_TOP_3D_BOTTOM: + { + m_All2DTop3DBottomLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ALL_2D_LEFT_3D_RIGHT: + { + m_All2DLeft3DRightLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ONE_BIG: + { + m_OneBigLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ONLY_2D_HORIZONTAL: + { + m_Only2DHorizontalLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ONLY_2D_VERTICAL: + { + m_Only2DVerticalLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ONE_TOP_3D_BOTTOM: + { + m_OneTop3DBottomLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ONE_LEFT_3D_RIGHT: + { + m_OneLeft3DRightLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ALL_HORIZONTAL: + { + m_AllHorizontalLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::ALL_VERTICAL: + { + m_AllVerticalLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::REMOVE_ONE: + { + m_RemoveOneLayoutAction->setEnabled(false); + break; + } + case LayoutDesign::NONE: + { + break; + } + } } -void QmitkRenderWindowMenu::CreateSettingsWidget() +#ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU +void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float opacity) +#else +void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float /*opacity*/) +#endif { - m_Settings = new QMenu(this); +#ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU + int X = floor(double(this->m_Parent->width() - this->width() - 8.0)); + int Y = 7; - m_DefaultLayoutAction = new QAction("standard layout", m_Settings); - m_DefaultLayoutAction->setDisabled(true); + QPoint pos = this->m_Parent->mapToGlobal(QPoint(0, 0)); - m_2DImagesUpLayoutAction = new QAction("2D images top, 3D bottom", m_Settings); - m_2DImagesUpLayoutAction->setDisabled(false); - - m_2DImagesLeftLayoutAction = new QAction("2D images left, 3D right", m_Settings); - m_2DImagesLeftLayoutAction->setDisabled(false); - - m_Big3DLayoutAction = new QAction("Big 3D", m_Settings); - m_Big3DLayoutAction->setDisabled(false); - - m_Widget1LayoutAction = new QAction("Axial plane", m_Settings); - m_Widget1LayoutAction->setDisabled(false); - - m_Widget2LayoutAction = new QAction("Sagittal plane", m_Settings); - m_Widget2LayoutAction->setDisabled(false); - - m_Widget3LayoutAction = new QAction("Coronal plane", m_Settings); - m_Widget3LayoutAction->setDisabled(false); - - m_RowWidget3And4LayoutAction = new QAction("Coronal top, 3D bottom", m_Settings); - m_RowWidget3And4LayoutAction->setDisabled(false); - - m_ColumnWidget3And4LayoutAction = new QAction("Coronal left, 3D right", m_Settings); - m_ColumnWidget3And4LayoutAction->setDisabled(false); - - m_SmallUpperWidget2Big3and4LayoutAction = new QAction("Sagittal top, Coronal n 3D bottom", m_Settings); - m_SmallUpperWidget2Big3and4LayoutAction->setDisabled(false); - - m_2x2Dand3DWidgetLayoutAction = new QAction("Axial n Sagittal left, 3D right", m_Settings); - m_2x2Dand3DWidgetLayoutAction->setDisabled(false); - - m_Left2Dand3DRight2DLayoutAction = new QAction("Axial n 3D left, Sagittal right", m_Settings); - m_Left2Dand3DRight2DLayoutAction->setDisabled(false); - - m_Settings->addAction(m_DefaultLayoutAction); - m_Settings->addAction(m_2DImagesUpLayoutAction); - m_Settings->addAction(m_2DImagesLeftLayoutAction); - m_Settings->addAction(m_Big3DLayoutAction); - m_Settings->addAction(m_Widget1LayoutAction); - m_Settings->addAction(m_Widget2LayoutAction); - m_Settings->addAction(m_Widget3LayoutAction); - m_Settings->addAction(m_RowWidget3And4LayoutAction); - m_Settings->addAction(m_ColumnWidget3And4LayoutAction); - m_Settings->addAction(m_SmallUpperWidget2Big3and4LayoutAction); - m_Settings->addAction(m_2x2Dand3DWidgetLayoutAction); - m_Settings->addAction(m_Left2Dand3DRight2DLayoutAction); - - m_Settings->setVisible(false); - - connect(m_DefaultLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToDefault(bool))); - connect(m_2DImagesUpLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutTo2DImagesUp(bool))); - connect(m_2DImagesLeftLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutTo2DImagesLeft(bool))); - connect(m_Big3DLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToBig3D(bool))); - connect(m_Widget1LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToWidget1(bool))); - connect(m_Widget2LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToWidget2(bool))); - connect(m_Widget3LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToWidget3(bool))); - connect(m_RowWidget3And4LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToRowWidget3And4(bool))); - connect( - m_ColumnWidget3And4LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToColumnWidget3And4(bool))); - connect(m_SmallUpperWidget2Big3and4LayoutAction, - SIGNAL(triggered(bool)), - this, - SLOT(OnChangeLayoutToSmallUpperWidget2Big3and4(bool))); - connect(m_2x2Dand3DWidgetLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutTo2x2Dand3DWidget(bool))); - connect( - m_Left2Dand3DRight2DLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToLeft2Dand3DRight2D(bool))); -} + this->move(X + pos.x(), Y + pos.y()); -void QmitkRenderWindowMenu::paintEvent(QPaintEvent * /*e*/) -{ - QPainter painter(this); - QColor semiTransparentColor = Qt::black; - semiTransparentColor.setAlpha(255); - painter.fillRect(rect(), semiTransparentColor); + if (opacity < 0) + opacity = 0; + else if (opacity > 1) + opacity = 1; + + this->setWindowOpacity(opacity); +#else + int moveX = floor(double(this->m_Parent->width() - this->width() - 4.0)); + this->move(moveX, 3); + this->show(); +#endif } -void QmitkRenderWindowMenu::SetLayoutIndex(unsigned int layoutIndex) +void QmitkRenderWindowMenu::ShowMenu() { - m_Layout = layoutIndex; + MITK_DEBUG << "menu showMenu"; + DeferredShowMenu(); } void QmitkRenderWindowMenu::HideMenu() { MITK_DEBUG << "menu hideEvent"; DeferredHideMenu(); } -void QmitkRenderWindowMenu::ShowMenu() +void QmitkRenderWindowMenu::paintEvent(QPaintEvent * /*e*/) { - MITK_DEBUG << "menu showMenu"; - DeferredShowMenu(); + QPainter painter(this); + QColor semiTransparentColor = Qt::black; + semiTransparentColor.setAlpha(255); + painter.fillRect(rect(), semiTransparentColor); } -void QmitkRenderWindowMenu::enterEvent(QEvent * /*e*/) +void QmitkRenderWindowMenu::CreateMenuWidget() { - MITK_DEBUG << "menu enterEvent"; - DeferredShowMenu(); + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setAlignment(Qt::AlignRight); + layout->setContentsMargins(1, 1, 1, 1); - m_Entered = true; -} + QSize size(13, 13); -void QmitkRenderWindowMenu::DeferredHideMenu() -{ - MITK_DEBUG << "menu deferredhidemenu"; -// Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows -// for macOS see bug 3192 -// for Windows see bug 12130 -//... so macOS and Windows must be treated differently: -#if defined(Q_OS_MAC) - this->setWindowOpacity(0.0f); -#else - this->setVisible(false); -#endif + m_CrosshairMenu = new QMenu(this); + connect(m_CrosshairMenu, &QMenu::aboutToShow, this, &QmitkRenderWindowMenu::OnCrosshairMenuAboutToShow); - // setVisible(false); - // setWindowOpacity(0.0f); - /// hide(); -} + m_CrosshairModeButton = new QToolButton(this); + m_CrosshairModeButton->setMaximumSize(15, 15); + m_CrosshairModeButton->setIconSize(size); + m_CrosshairModeButton->setMenu(m_CrosshairMenu); + m_CrosshairModeButton->setIcon(QIcon(QPixmap(iconCrosshairMode_xpm))); + m_CrosshairModeButton->setPopupMode(QToolButton::InstantPopup); + m_CrosshairModeButton->setStyleSheet("QToolButton::menu-indicator { image: none; }"); + m_CrosshairModeButton->setAutoRaise(true); + layout->addWidget(m_CrosshairModeButton); -void QmitkRenderWindowMenu::leaveEvent(QEvent * /*e*/) -{ - MITK_DEBUG << "menu leaveEvent"; + m_FullScreenButton = new QToolButton(this); + m_FullScreenButton->setMaximumSize(15, 15); + m_FullScreenButton->setIconSize(size); + m_FullScreenButton->setIcon(QIcon(QPixmap(iconFullScreen_xpm))); + m_FullScreenButton->setAutoRaise(true); + layout->addWidget(m_FullScreenButton); - m_Entered = false; - smoothHide(); -} + m_LayoutDesignButton = new QToolButton(this); + m_LayoutDesignButton->setMaximumSize(15, 15); + m_LayoutDesignButton->setIconSize(size); + m_LayoutDesignButton->setIcon(QIcon(QPixmap(iconSettings_xpm))); + m_LayoutDesignButton->setAutoRaise(true); + layout->addWidget(m_LayoutDesignButton); -/* This method is responsible for non fluttering of - the renderWindowMenu when mouse cursor moves along the renderWindowMenu*/ -void QmitkRenderWindowMenu::smoothHide() -{ - MITK_DEBUG << "menu leaveEvent"; - m_HideTimer.start(10); + connect(m_FullScreenButton, &QToolButton::clicked, this, &QmitkRenderWindowMenu::OnFullScreenButton); + connect(m_LayoutDesignButton, &QToolButton::clicked, this, &QmitkRenderWindowMenu::OnLayoutDesignButton); } -void QmitkRenderWindowMenu::ChangeFullScreenMode(bool state) -{ - this->OnFullScreenButton(state); -} -/// \brief -void QmitkRenderWindowMenu::OnFullScreenButton(bool /*checked*/) +void QmitkRenderWindowMenu::CreateSettingsWidget() { - if (!m_FullScreenMode) - { - m_FullScreenMode = true; - m_OldLayoutDesign = m_LayoutDesign; + m_LayoutActionsMenu = new QMenu(this); - switch (m_Layout) - { - case AXIAL: - { - emit SignalChangeLayoutDesign(LAYOUT_AXIAL); - break; - } + m_DefaultLayoutAction = new QAction("Standard layout", m_LayoutActionsMenu); + m_DefaultLayoutAction->setDisabled(true); - case SAGITTAL: - { - emit SignalChangeLayoutDesign(LAYOUT_SAGITTAL); - break; - } - case CORONAL: - { - emit SignalChangeLayoutDesign(LAYOUT_CORONAL); - break; - } - case THREE_D: - { - emit SignalChangeLayoutDesign(LAYOUT_BIG3D); - break; - } - } + m_All2DTop3DBottomLayoutAction = new QAction("All 2D top, 3D bottom", m_LayoutActionsMenu); + m_All2DTop3DBottomLayoutAction->setDisabled(false); - // Move Widget and show again - this->MoveWidgetToCorrectPos(1.0f); + m_All2DLeft3DRightLayoutAction = new QAction("All 2D left, 3D right", m_LayoutActionsMenu); + m_All2DLeft3DRightLayoutAction->setDisabled(false); - // change icon - this->ChangeFullScreenIcon(); - } - else - { - m_FullScreenMode = false; - emit SignalChangeLayoutDesign(m_OldLayoutDesign); + m_OneBigLayoutAction = new QAction("This big", m_LayoutActionsMenu); + m_OneBigLayoutAction->setDisabled(false); - // Move Widget and show again - this->MoveWidgetToCorrectPos(1.0f); + m_Only2DHorizontalLayoutAction = new QAction("Only 2D horizontal", m_LayoutActionsMenu); + m_Only2DHorizontalLayoutAction->setDisabled(false); - // change icon - this->ChangeFullScreenIcon(); - } + m_Only2DVerticalLayoutAction = new QAction("Only 2D vertical", m_LayoutActionsMenu); + m_Only2DVerticalLayoutAction->setDisabled(false); - DeferredShowMenu(); -} + m_OneTop3DBottomLayoutAction = new QAction("This top, 3D bottom", m_LayoutActionsMenu); + m_OneTop3DBottomLayoutAction->setDisabled(false); -/// \brief -void QmitkRenderWindowMenu::OnSettingsButton(bool /*checked*/) -{ - if (m_Settings == nullptr) - this->CreateSettingsWidget(); + m_OneLeft3DRightLayoutAction = new QAction("This left, 3D right", m_LayoutActionsMenu); + m_OneLeft3DRightLayoutAction->setDisabled(false); - QPoint point = this->mapToGlobal(m_SettingsButton->geometry().topLeft()); - m_Settings->setVisible(true); - m_Settings->exec(point); -} + m_AllHorizontalLayoutAction = new QAction("All horizontal", m_LayoutActionsMenu); + m_AllHorizontalLayoutAction->setDisabled(false); -void QmitkRenderWindowMenu::OnChangeLayoutTo2DImagesUp(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); + m_AllVerticalLayoutAction = new QAction("All vertical", m_LayoutActionsMenu); + m_AllVerticalLayoutAction->setDisabled(false); - m_LayoutDesign = LAYOUT_2DIMAGEUP; - emit SignalChangeLayoutDesign(LAYOUT_2DIMAGEUP); + m_RemoveOneLayoutAction = new QAction("Remove this", m_LayoutActionsMenu); + m_RemoveOneLayoutAction->setDisabled(false); - DeferredShowMenu(); -} -void QmitkRenderWindowMenu::OnChangeLayoutTo2DImagesLeft(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); + m_LayoutActionsMenu->addAction(m_DefaultLayoutAction); + m_LayoutActionsMenu->addAction(m_All2DTop3DBottomLayoutAction); + m_LayoutActionsMenu->addAction(m_All2DLeft3DRightLayoutAction); + m_LayoutActionsMenu->addAction(m_OneBigLayoutAction); + m_LayoutActionsMenu->addAction(m_Only2DHorizontalLayoutAction); + m_LayoutActionsMenu->addAction(m_Only2DVerticalLayoutAction); + m_LayoutActionsMenu->addAction(m_OneTop3DBottomLayoutAction); + m_LayoutActionsMenu->addAction(m_OneLeft3DRightLayoutAction); + m_LayoutActionsMenu->addAction(m_AllHorizontalLayoutAction); + m_LayoutActionsMenu->addAction(m_AllVerticalLayoutAction); + m_LayoutActionsMenu->addAction(m_RemoveOneLayoutAction); - m_LayoutDesign = LAYOUT_2DIMAGELEFT; - emit SignalChangeLayoutDesign(LAYOUT_2DIMAGELEFT); + m_LayoutActionsMenu->setVisible(false); - DeferredShowMenu(); + connect(m_DefaultLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::DEFAULT); }); + connect(m_All2DTop3DBottomLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_2D_TOP_3D_BOTTOM); }); + connect(m_All2DLeft3DRightLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_2D_LEFT_3D_RIGHT); }); + connect(m_OneBigLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_BIG); }); + connect(m_Only2DHorizontalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONLY_2D_HORIZONTAL); }); + connect(m_Only2DVerticalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONLY_2D_VERTICAL); }); + connect(m_OneTop3DBottomLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_TOP_3D_BOTTOM); }); + connect(m_OneLeft3DRightLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_LEFT_3D_RIGHT); }); + connect(m_AllHorizontalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_HORIZONTAL); }); + connect(m_AllVerticalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_VERTICAL); }); + connect(m_RemoveOneLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::REMOVE_ONE); }); } -void QmitkRenderWindowMenu::OnChangeLayoutToDefault(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - m_LayoutDesign = LAYOUT_DEFAULT; - emit SignalChangeLayoutDesign(LAYOUT_DEFAULT); - - DeferredShowMenu(); +void QmitkRenderWindowMenu::ChangeFullScreenIcon() +{ + m_FullScreenButton->setIcon(m_FullScreenMode ? QPixmap(iconLeaveFullScreen_xpm) : QPixmap(iconFullScreen_xpm)); } void QmitkRenderWindowMenu::DeferredShowMenu() { MITK_DEBUG << "deferred show menu"; - m_HideTimer.stop(); + m_HideTimer->stop(); -// Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows -// for macOS see bug 3192 -// for Windows see bug 12130 -//... so macOS and Windows must be treated differently: + // Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows + // for macOS see bug 3192 + // for Windows see bug 12130 + //... so macOS and Windows must be treated differently: #if defined(Q_OS_MAC) this->setWindowOpacity(1.0f); #else this->setVisible(true); this->raise(); #endif } -void QmitkRenderWindowMenu::OnChangeLayoutToBig3D(bool) -{ - MITK_DEBUG << "OnChangeLayoutToBig3D"; - - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_BIG3D; - emit SignalChangeLayoutDesign(LAYOUT_BIG3D); - - DeferredShowMenu(); -} - -void QmitkRenderWindowMenu::OnChangeLayoutToWidget1(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_AXIAL; - emit SignalChangeLayoutDesign(LAYOUT_AXIAL); - - DeferredShowMenu(); -} -void QmitkRenderWindowMenu::OnChangeLayoutToWidget2(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_SAGITTAL; - emit SignalChangeLayoutDesign(LAYOUT_SAGITTAL); - - DeferredShowMenu(); -} -void QmitkRenderWindowMenu::OnChangeLayoutToWidget3(bool) +void QmitkRenderWindowMenu::DeferredHideMenu() { - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_CORONAL; - emit SignalChangeLayoutDesign(LAYOUT_CORONAL); - - DeferredShowMenu(); + MITK_DEBUG << "menu deferredhidemenu"; + // Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows + // for macOS see bug 3192 + // for Windows see bug 12130 + //... so macOS and Windows must be treated differently: +#if defined(Q_OS_MAC) + this->setWindowOpacity(0.0f); +#else + this->setVisible(false); +#endif } -void QmitkRenderWindowMenu::OnChangeLayoutToRowWidget3And4(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_ROWWIDGET3AND4; - emit SignalChangeLayoutDesign(LAYOUT_ROWWIDGET3AND4); - DeferredShowMenu(); -} -void QmitkRenderWindowMenu::OnChangeLayoutToColumnWidget3And4(bool) +void QmitkRenderWindowMenu::smoothHide() { - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_COLUMNWIDGET3AND4; - emit SignalChangeLayoutDesign(LAYOUT_COLUMNWIDGET3AND4); - - DeferredShowMenu(); + MITK_DEBUG << "menu leaveEvent"; + m_HideTimer->start(10); } -void QmitkRenderWindowMenu::OnChangeLayoutToSmallUpperWidget2Big3and4(bool) +void QmitkRenderWindowMenu::enterEvent(QEvent * /*e*/) { - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_SMALLUPPERWIDGET2BIGAND4; - emit SignalChangeLayoutDesign(LAYOUT_SMALLUPPERWIDGET2BIGAND4); - + MITK_DEBUG << "menu enterEvent"; DeferredShowMenu(); } -void QmitkRenderWindowMenu::OnChangeLayoutTo2x2Dand3DWidget(bool) -{ - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - m_LayoutDesign = LAYOUT_2X2DAND3DWIDGET; - emit SignalChangeLayoutDesign(LAYOUT_2X2DAND3DWIDGET); - - DeferredShowMenu(); -} -void QmitkRenderWindowMenu::OnChangeLayoutToLeft2Dand3DRight2D(bool) +void QmitkRenderWindowMenu::leaveEvent(QEvent * /*e*/) { - // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List - m_FullScreenMode = false; - this->ChangeFullScreenIcon(); - - m_LayoutDesign = LAYOUT_LEFT2DAND3DRIGHT2D; - emit SignalChangeLayoutDesign(LAYOUT_LEFT2DAND3DRIGHT2D); - - DeferredShowMenu(); + MITK_DEBUG << "menu leaveEvent"; + smoothHide(); } -void QmitkRenderWindowMenu::UpdateLayoutDesignList(int layoutDesignIndex) +void QmitkRenderWindowMenu::AutoRotateNextStep() { - m_LayoutDesign = layoutDesignIndex; - - if (m_Settings == nullptr) - this->CreateSettingsWidget(); - - switch (m_LayoutDesign) + if (m_Renderer->GetCameraRotationController()) { - case LAYOUT_DEFAULT: - { - m_DefaultLayoutAction->setEnabled(false); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - - case LAYOUT_2DIMAGEUP: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(false); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_2DIMAGELEFT: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(false); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_BIG3D: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(false); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_AXIAL: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(false); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_SAGITTAL: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(false); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_CORONAL: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(false); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_2X2DAND3DWIDGET: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(false); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_ROWWIDGET3AND4: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(false); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_COLUMNWIDGET3AND4: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(false); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_SMALLUPPERWIDGET2BIGAND4: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(false); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(true); - break; - } - case LAYOUT_LEFT2DAND3DRIGHT2D: - { - m_DefaultLayoutAction->setEnabled(true); - m_2DImagesUpLayoutAction->setEnabled(true); - m_2DImagesLeftLayoutAction->setEnabled(true); - m_Big3DLayoutAction->setEnabled(true); - m_Widget1LayoutAction->setEnabled(true); - m_Widget2LayoutAction->setEnabled(true); - m_Widget3LayoutAction->setEnabled(true); - m_RowWidget3And4LayoutAction->setEnabled(true); - m_ColumnWidget3And4LayoutAction->setEnabled(true); - m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); - m_2x2Dand3DWidgetLayoutAction->setEnabled(true); - m_Left2Dand3DRight2DLayoutAction->setEnabled(false); - break; - } + m_Renderer->GetCameraRotationController()->GetSlice()->Next(); } } -#ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU -void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float opacity) -#else -void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float /*opacity*/) -#endif -{ -#ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU - int X = floor(double(this->m_Parent->width() - this->width() - 8.0)); - int Y = 7; - - QPoint pos = this->m_Parent->mapToGlobal(QPoint(0, 0)); - - this->move(X + pos.x(), Y + pos.y()); - - if (opacity < 0) - opacity = 0; - else if (opacity > 1) - opacity = 1; - - this->setWindowOpacity(opacity); -#else - int moveX = floor(double(this->m_Parent->width() - this->width() - 4.0)); - this->move(moveX, 3); - this->show(); -#endif -} - -void QmitkRenderWindowMenu::ChangeFullScreenIcon() -{ - m_FullScreenButton->setIcon(m_FullScreenMode ? QPixmap(iconLeaveFullScreen_xpm) : QPixmap(iconFullScreen_xpm)); -} - -void QmitkRenderWindowMenu::OnCrosshairRotationModeSelected(QAction *action) -{ - MITK_DEBUG << "selected crosshair mode " << action->data().toInt(); - emit ChangeCrosshairRotationMode(action->data().toInt()); -} - -void QmitkRenderWindowMenu::SetCrossHairVisibility(bool state) +void QmitkRenderWindowMenu::OnAutoRotationActionTriggered() { - if (m_Renderer.IsNotNull()) + if (m_AutoRotationTimer->isActive()) { - mitk::DataNode *n; - if (this->m_MultiWidget) - { - n = this->m_MultiWidget->GetWidgetPlane1(); - if (n) - n->SetVisibility(state); - n = this->m_MultiWidget->GetWidgetPlane2(); - if (n) - n->SetVisibility(state); - n = this->m_MultiWidget->GetWidgetPlane3(); - if (n) - n->SetVisibility(state); - m_Renderer->GetRenderingManager()->RequestUpdateAll(); - } + m_AutoRotationTimer->stop(); + m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOff(); + } + else + { + m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOn(); + m_AutoRotationTimer->start(); } } void QmitkRenderWindowMenu::OnTSNumChanged(int num) { MITK_DEBUG << "Thickslices num: " << num << " on renderer " << m_Renderer.GetPointer(); if (m_Renderer.IsNotNull()) { unsigned int thickSlicesMode = 0; // determine the state of the thick-slice mode mitk::ResliceMethodProperty *resliceMethodEnumProperty = nullptr; if(m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty(resliceMethodEnumProperty, "reslice.thickslices") && resliceMethodEnumProperty) { thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); if(thickSlicesMode!=0) m_DefaultThickMode = thickSlicesMode; } if(thickSlicesMode==0 && num>0) //default mode only for single slices { thickSlicesMode = m_DefaultThickMode; //mip default m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea", mitk::BoolProperty::New(true)); } if(num<1) { thickSlicesMode = 0; m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea", mitk::BoolProperty::New(false)); } m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New(thickSlicesMode)); m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(num)); m_TSLabel->setText(QString::number(num * 2 + 1)); m_Renderer->SendUpdateSlice(); m_Renderer->GetRenderingManager()->RequestUpdateAll(); } } -void QmitkRenderWindowMenu::OnCrossHairMenuAboutToShow() +void QmitkRenderWindowMenu::OnCrosshairMenuAboutToShow() { QMenu *crosshairModesMenu = m_CrosshairMenu; crosshairModesMenu->clear(); QAction *resetViewAction = new QAction(crosshairModesMenu); resetViewAction->setText("Reset view"); crosshairModesMenu->addAction(resetViewAction); - connect(resetViewAction, SIGNAL(triggered()), this, SIGNAL(ResetView())); + connect(resetViewAction, &QAction::triggered, this, &QmitkRenderWindowMenu::ResetView); // Show hide crosshairs { - bool currentState = true; - - if (m_Renderer.IsNotNull()) - { - mitk::DataStorage *ds = m_Renderer->GetDataStorage(); - mitk::DataNode *n; - if (ds) - { - n = this->m_MultiWidget->GetWidgetPlane1(); - if (n) - { - bool v; - if (n->GetVisibility(v, nullptr)) - currentState &= v; - } - n = this->m_MultiWidget->GetWidgetPlane2(); - if (n) - { - bool v; - if (n->GetVisibility(v, nullptr)) - currentState &= v; - } - n = this->m_MultiWidget->GetWidgetPlane3(); - if (n) - { - bool v; - if (n->GetVisibility(v, nullptr)) - currentState &= v; - } - } - } - QAction *showHideCrosshairVisibilityAction = new QAction(crosshairModesMenu); showHideCrosshairVisibilityAction->setText("Show crosshair"); showHideCrosshairVisibilityAction->setCheckable(true); - showHideCrosshairVisibilityAction->setChecked(currentState); + showHideCrosshairVisibilityAction->setChecked(m_CrosshairVisibility); crosshairModesMenu->addAction(showHideCrosshairVisibilityAction); - connect(showHideCrosshairVisibilityAction, SIGNAL(toggled(bool)), this, SLOT(SetCrossHairVisibility(bool))); + connect(showHideCrosshairVisibilityAction, &QAction::toggled, this, &QmitkRenderWindowMenu::OnCrosshairVisibilityChanged); } // Rotation mode { QAction *rotationGroupSeparator = new QAction(crosshairModesMenu); rotationGroupSeparator->setSeparator(true); rotationGroupSeparator->setText("Rotation mode"); crosshairModesMenu->addAction(rotationGroupSeparator); QActionGroup *rotationModeActionGroup = new QActionGroup(crosshairModesMenu); rotationModeActionGroup->setExclusive(true); QAction *noCrosshairRotation = new QAction(crosshairModesMenu); noCrosshairRotation->setActionGroup(rotationModeActionGroup); noCrosshairRotation->setText("No crosshair rotation"); noCrosshairRotation->setCheckable(true); - noCrosshairRotation->setChecked(currentCrosshairRotationMode == 0); + noCrosshairRotation->setChecked(m_CrosshairRotationMode == 0); noCrosshairRotation->setData(0); crosshairModesMenu->addAction(noCrosshairRotation); QAction *singleCrosshairRotation = new QAction(crosshairModesMenu); singleCrosshairRotation->setActionGroup(rotationModeActionGroup); singleCrosshairRotation->setText("Crosshair rotation"); singleCrosshairRotation->setCheckable(true); - singleCrosshairRotation->setChecked(currentCrosshairRotationMode == 1); + singleCrosshairRotation->setChecked(m_CrosshairRotationMode == 1); singleCrosshairRotation->setData(1); crosshairModesMenu->addAction(singleCrosshairRotation); QAction *coupledCrosshairRotation = new QAction(crosshairModesMenu); coupledCrosshairRotation->setActionGroup(rotationModeActionGroup); coupledCrosshairRotation->setText("Coupled crosshair rotation"); coupledCrosshairRotation->setCheckable(true); - coupledCrosshairRotation->setChecked(currentCrosshairRotationMode == 2); + coupledCrosshairRotation->setChecked(m_CrosshairRotationMode == 2); coupledCrosshairRotation->setData(2); crosshairModesMenu->addAction(coupledCrosshairRotation); QAction *swivelMode = new QAction(crosshairModesMenu); swivelMode->setActionGroup(rotationModeActionGroup); swivelMode->setText("Swivel mode"); swivelMode->setCheckable(true); - swivelMode->setChecked(currentCrosshairRotationMode == 3); + swivelMode->setChecked(m_CrosshairRotationMode == 3); swivelMode->setData(3); crosshairModesMenu->addAction(swivelMode); - connect( - rotationModeActionGroup, SIGNAL(triggered(QAction *)), this, SLOT(OnCrosshairRotationModeSelected(QAction *))); + connect(rotationModeActionGroup, &QActionGroup::triggered, this, &QmitkRenderWindowMenu::OnCrosshairRotationModeSelected); } // auto rotation support if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D) { QAction *autoRotationGroupSeparator = new QAction(crosshairModesMenu); autoRotationGroupSeparator->setSeparator(true); crosshairModesMenu->addAction(autoRotationGroupSeparator); QAction *autoRotationAction = crosshairModesMenu->addAction("Auto Rotation"); autoRotationAction->setCheckable(true); - autoRotationAction->setChecked(m_AutoRotationTimer.isActive()); - connect(autoRotationAction, SIGNAL(triggered()), this, SLOT(OnAutoRotationActionTriggered())); + autoRotationAction->setChecked(m_AutoRotationTimer->isActive()); + connect(autoRotationAction, &QAction::triggered, this, &QmitkRenderWindowMenu::OnAutoRotationActionTriggered); } // Thickslices support if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { QAction *thickSlicesGroupSeparator = new QAction(crosshairModesMenu); thickSlicesGroupSeparator->setSeparator(true); thickSlicesGroupSeparator->setText("ThickSlices mode"); crosshairModesMenu->addAction(thickSlicesGroupSeparator); QActionGroup *thickSlicesActionGroup = new QActionGroup(crosshairModesMenu); thickSlicesActionGroup->setExclusive(true); int currentMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast( m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices")); if (m.IsNotNull()) currentMode = m->GetValueAsId(); } int currentNum = 1; { mitk::IntProperty::Pointer m = dynamic_cast( m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices.num")); if (m.IsNotNull()) { currentNum = m->GetValue(); } } if (currentMode == 0) currentNum = 0; QSlider *m_TSSlider = new QSlider(crosshairModesMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(50); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); - connect(m_TSSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTSNumChanged(int))); + connect(m_TSSlider, &QSlider::valueChanged, this, &QmitkRenderWindowMenu::OnTSNumChanged); - QHBoxLayout *_TSLayout = new QHBoxLayout; - _TSLayout->setContentsMargins(4, 4, 4, 4); - _TSLayout->addWidget(new QLabel("TS: ")); - _TSLayout->addWidget(m_TSSlider); - _TSLayout->addWidget(m_TSLabel = new QLabel(QString::number(currentNum * 2 + 1), this)); + QHBoxLayout *tsLayout = new QHBoxLayout; + tsLayout->setContentsMargins(4, 4, 4, 4); + tsLayout->addWidget(new QLabel("TS: ")); + tsLayout->addWidget(m_TSSlider); + tsLayout->addWidget(m_TSLabel = new QLabel(QString::number(currentNum * 2 + 1), this)); - QWidget *_TSWidget = new QWidget; - _TSWidget->setLayout(_TSLayout); + QWidget *tsWidget = new QWidget; + tsWidget->setLayout(tsLayout); QWidgetAction *m_TSSliderAction = new QWidgetAction(crosshairModesMenu); - m_TSSliderAction->setDefaultWidget(_TSWidget); + m_TSSliderAction->setDefaultWidget(tsWidget); crosshairModesMenu->addAction(m_TSSliderAction); } } -void QmitkRenderWindowMenu::NotifyNewWidgetPlanesMode(int mode) +void QmitkRenderWindowMenu::OnCrosshairVisibilityChanged(bool visible) { - currentCrosshairRotationMode = mode; + m_CrosshairVisibility = visible; + emit CrosshairVisibilityChanged(visible); } -void QmitkRenderWindowMenu::OnAutoRotationActionTriggered() +void QmitkRenderWindowMenu::OnCrosshairRotationModeSelected(QAction *action) { - if (m_AutoRotationTimer.isActive()) + m_CrosshairRotationMode = action->data().toInt(); + emit CrosshairRotationModeChanged(m_CrosshairRotationMode); +} + +void QmitkRenderWindowMenu::OnFullScreenButton(bool /*checked*/) +{ + if (!m_FullScreenMode) { - m_AutoRotationTimer.stop(); - m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOff(); + m_FullScreenMode = true; + m_OldLayoutDesign = m_LayoutDesign; + + emit LayoutDesignChanged(LayoutDesign::ONE_BIG); } else { - m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOn(); - m_AutoRotationTimer.start(); + m_FullScreenMode = false; + emit LayoutDesignChanged(m_OldLayoutDesign); } + + MoveWidgetToCorrectPos(1.0f); + ChangeFullScreenIcon(); + + DeferredShowMenu(); } -void QmitkRenderWindowMenu::AutoRotateNextStep() +void QmitkRenderWindowMenu::OnLayoutDesignButton(bool /*checked*/) { - if (m_Renderer->GetCameraRotationController()) - m_Renderer->GetCameraRotationController()->GetSlice()->Next(); + if (nullptr == m_LayoutActionsMenu) + { + CreateSettingsWidget(); + } + + QPoint point = mapToGlobal(m_LayoutDesignButton->geometry().topLeft()); + m_LayoutActionsMenu->setVisible(true); + m_LayoutActionsMenu->exec(point); +} + +void QmitkRenderWindowMenu::OnSetLayout(LayoutDesign layoutDesign) +{ + m_FullScreenMode = false; + ChangeFullScreenIcon(); + + m_LayoutDesign = layoutDesign; + emit LayoutDesignChanged(m_LayoutDesign); + + DeferredShowMenu(); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index f607f51ab4..d4d4bc0c93 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,250 +1,268 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindowWidget.h" -// mitk qt widgets -#include - // vtk +#include #include QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, const QString& widgetName/* = ""*/, mitk::DataStorage* dataStorage/* = nullptr*/, + mitk::RenderingManager* renderingManager/* = nullptr*/, mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/) - : QWidget(parent) + : QFrame(parent) , m_WidgetName(widgetName) , m_DataStorage(dataStorage) - , m_RenderWindow(nullptr) + , m_RenderingManager(renderingManager) , m_RenderingMode(renderingMode) + , m_RenderWindow(nullptr) , m_PointSetNode(nullptr) , m_PointSet(nullptr) { InitializeGUI(); } QmitkRenderWindowWidget::~QmitkRenderWindowWidget() { auto sliceNavigationController = m_RenderWindow->GetSliceNavigationController(); if (nullptr != sliceNavigationController) { sliceNavigationController->SetCrosshairEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); } if (nullptr != m_DataStorage) { m_DataStorage->Remove(m_PointSetNode); } } void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; if (nullptr != m_RenderWindow) { mitk::BaseRenderer::GetInstance(m_RenderWindow->GetRenderWindow())->SetDataStorage(dataStorage); } } mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } void QmitkRenderWindowWidget::RequestUpdate() { m_RenderingManager->RequestUpdate(m_RenderWindow->GetRenderWindow()); } void QmitkRenderWindowWidget::ForceImmediateUpdate() { m_RenderingManager->ForceImmediateUpdate(m_RenderWindow->GetRenderWindow()); } void QmitkRenderWindowWidget::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } m_GradientBackgroundColors.first = upper; m_GradientBackgroundColors.second = lower; vtkRenderer->SetBackground(lower[0], lower[1], lower[2]); vtkRenderer->SetBackground2(upper[0], upper[1], upper[2]); ShowGradientBackground(true); } void QmitkRenderWindowWidget::ShowGradientBackground(bool show) { m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetGradientBackground(show); } bool QmitkRenderWindowWidget::IsGradientBackgroundOn() const { return m_RenderWindow->GetRenderer()->GetVtkRenderer()->GetGradientBackground(); } void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) { m_DecorationColor = color; - m_RectangleProp->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); - m_CornerAnnotation->GetTextProperty()->SetColor(color[0], color[1], color[2]); + m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); + + QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); + setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); } void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) { - m_RectangleProp->SetVisibility(show); + if (show) + { + setFrameStyle(QFrame::Box | QFrame::Plain); + } + else + { + setFrameStyle(NoFrame); + } } bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const { - return m_RectangleProp->GetVisibility() > 0; + return frameStyle() > 0; } void QmitkRenderWindowWidget::ShowCornerAnnotation(bool show) { m_CornerAnnotation->SetVisibility(show); } bool QmitkRenderWindowWidget::IsCornerAnnotationVisible() const { return m_CornerAnnotation->GetVisibility() > 0; } void QmitkRenderWindowWidget::SetCornerAnnotationText(const std::string& cornerAnnotation) { m_CornerAnnotation->SetText(0, cornerAnnotation.c_str()); } std::string QmitkRenderWindowWidget::GetCornerAnnotationText() const { return std::string(m_CornerAnnotation->GetText(0)); } bool QmitkRenderWindowWidget::IsRenderWindowMenuActivated() const { return m_RenderWindow->GetActivateMenuWidgetFlag(); } void QmitkRenderWindowWidget::ActivateCrosshair(bool activate) { if (nullptr == m_DataStorage) { return; } if (activate) { try { m_DataStorage->Add(m_PointSetNode); } catch(std::invalid_argument& /*e*/) { // crosshair already existing return; } } else { m_DataStorage->Remove(m_PointSetNode); } } void QmitkRenderWindowWidget::InitializeGUI() { m_Layout = new QHBoxLayout(this); m_Layout->setMargin(0); setLayout(m_Layout); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setContentsMargins(0, 0, 0, 0); + + if (nullptr == m_DataStorage) + { + return; + } + + if (nullptr == m_RenderingManager) + { + return; + } - // create render window for this render window widget - m_RenderingManager = mitk::RenderingManager::GetInstance(); - //m_RenderingManager = mitk::RenderingManager::New(); m_RenderingManager->SetDataStorage(m_DataStorage); + // create render window for this render window widget m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr, m_RenderingManager, m_RenderingMode); - m_RenderWindow->SetLayoutIndex(mitk::SliceNavigationController::Sagittal); + m_RenderWindow->SetLayoutIndex(mitk::BaseRenderer::ViewDirection::SAGITTAL); m_RenderWindow->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); m_RenderWindow->GetSliceNavigationController()->SetRenderingManager(m_RenderingManager); m_RenderWindow->GetSliceNavigationController()->SetCrosshairEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); + connect(m_RenderWindow, &QVTKOpenGLWidget::mouseEvent, this, &QmitkRenderWindowWidget::MouseEvent); + mitk::TimeGeometry::ConstPointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); m_RenderingManager->InitializeViews(timeGeometry); m_Layout->addWidget(m_RenderWindow); // add point set as a crosshair m_PointSetNode = mitk::DataNode::New(); m_PointSetNode->SetProperty("name", mitk::StringProperty::New("Crosshair of render window " + m_WidgetName.toStdString())); m_PointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); // crosshair-node should typically be invisible // set the crosshair only visible for this specific renderer m_PointSetNode->SetBoolProperty("fixedLayer", true, m_RenderWindow->GetRenderer()); m_PointSetNode->SetVisibility(true, m_RenderWindow->GetRenderer()); m_PointSetNode->SetVisibility(false); m_PointSet = mitk::PointSet::New(); m_PointSetNode->SetData(m_PointSet); // set colors and corner annotation InitializeDecorations(); } void QmitkRenderWindowWidget::InitializeDecorations() { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } // initialize background color gradients float black[3] = { 0.0f, 0.0f, 0.0f }; SetGradientBackgroundColors(black, black); // initialize decoration color, rectangle and annotation text float white[3] = { 1.0f, 1.0f, 1.0f }; m_DecorationColor = white; - m_RectangleProp = vtkSmartPointer::New(); - m_RectangleProp->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); - if (0 == vtkRenderer->HasViewProp(m_RectangleProp)) - { - vtkRenderer->AddViewProp(m_RectangleProp); - } + + setFrameStyle(QFrame::Box | QFrame::Plain); + QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); + setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); m_CornerAnnotation = vtkSmartPointer::New(); m_CornerAnnotation->SetText(0, "Sagittal"); m_CornerAnnotation->SetMaximumFontSize(12); m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) { vtkRenderer->AddViewProp(m_CornerAnnotation); } } void QmitkRenderWindowWidget::SetCrosshair(mitk::Point3D selectedPoint) { m_PointSet->SetPoint(1, selectedPoint, 0); - mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); + m_RenderingManager->RequestUpdate(m_RenderWindow->GetRenderWindow()); } diff --git a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp index f9e7793ee2..87ca55e6bb 100644 --- a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp @@ -1,2034 +1,808 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" +#include "QmitkRenderWindowWidget.h" -#include -#include -#include -#include -#include -#include -#include - -#include "mitkImagePixelReadAccessor.h" -#include "mitkPixelTypeMultiplex.h" -#include +// mitk core #include -#include #include +#include #include #include #include #include #include #include +#include #include #include #include #include #include + +// qt +#include +#include +#include + +// vtk #include -#include -#include -#include -#include +// c++ #include QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget *parent, - Qt::WindowFlags f, - mitk::RenderingManager *renderingManager, - mitk::BaseRenderer::RenderingMode::Type renderingMode, - const QString &name) - : QWidget(parent, f), - mitkWidget1(nullptr), - mitkWidget2(nullptr), - mitkWidget3(nullptr), - mitkWidget4(nullptr), - levelWindowWidget(nullptr), - QmitkStdMultiWidgetLayout(nullptr), - m_Layout(LAYOUT_DEFAULT), - m_PlaneMode(PLANE_MODE_SLICING), - m_RenderingManager(renderingManager), - m_GradientBackgroundFlag(true), - m_TimeNavigationController(nullptr), - m_MainSplit(nullptr), - m_LayoutSplit(nullptr), - m_SubSplit1(nullptr), - m_SubSplit2(nullptr), - mitkWidget1Container(nullptr), - mitkWidget2Container(nullptr), - mitkWidget3Container(nullptr), - mitkWidget4Container(nullptr), - m_PendingCrosshairPositionEvent(false), - m_CrosshairNavigationEnabled(false) + Qt::WindowFlags f/* = 0*/, + mitk::RenderingManager *renderingManager/* = nullptr*/, + mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, + const QString &name/* = "stdmulti"*/) + : QmitkAbstractMultiWidget(parent, f, renderingManager, renderingMode, name) + , m_TimeNavigationController(nullptr) + , m_PendingCrosshairPositionEvent(false) { - /****************************************************** - * Use the global RenderingManager if none was specified - * ****************************************************/ - if (m_RenderingManager == nullptr) - { - m_RenderingManager = mitk::RenderingManager::GetInstance(); - } - m_TimeNavigationController = m_RenderingManager->GetTimeNavigationController(); - - /*******************************/ - // Create Widget manually - /*******************************/ - - // create Layouts - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - QmitkStdMultiWidgetLayout->setContentsMargins(0, 0, 0, 0); - - // Set Layout to widget - this->setLayout(QmitkStdMultiWidgetLayout); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(Qt::Vertical, m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // creae Widget Container - mitkWidget1Container = new QWidget(m_SubSplit1); - mitkWidget2Container = new QWidget(m_SubSplit1); - mitkWidget3Container = new QWidget(m_SubSplit2); - mitkWidget4Container = new QWidget(m_SubSplit2); - - mitkWidget1Container->setContentsMargins(0, 0, 0, 0); - mitkWidget2Container->setContentsMargins(0, 0, 0, 0); - mitkWidget3Container->setContentsMargins(0, 0, 0, 0); - mitkWidget4Container->setContentsMargins(0, 0, 0, 0); - - // create Widget Layout - QHBoxLayout *mitkWidgetLayout1 = new QHBoxLayout(mitkWidget1Container); - QHBoxLayout *mitkWidgetLayout2 = new QHBoxLayout(mitkWidget2Container); - QHBoxLayout *mitkWidgetLayout3 = new QHBoxLayout(mitkWidget3Container); - QHBoxLayout *mitkWidgetLayout4 = new QHBoxLayout(mitkWidget4Container); - - m_CornerAnnotations[0] = vtkSmartPointer::New(); - m_CornerAnnotations[1] = vtkSmartPointer::New(); - m_CornerAnnotations[2] = vtkSmartPointer::New(); - m_CornerAnnotations[3] = vtkSmartPointer::New(); - - m_RectangleProps[0] = vtkSmartPointer::New(); - m_RectangleProps[1] = vtkSmartPointer::New(); - m_RectangleProps[2] = vtkSmartPointer::New(); - m_RectangleProps[3] = vtkSmartPointer::New(); - - mitkWidgetLayout1->setMargin(0); - mitkWidgetLayout2->setMargin(0); - mitkWidgetLayout3->setMargin(0); - mitkWidgetLayout4->setMargin(0); - - // set Layout to Widget Container - mitkWidget1Container->setLayout(mitkWidgetLayout1); - mitkWidget2Container->setLayout(mitkWidgetLayout2); - mitkWidget3Container->setLayout(mitkWidgetLayout3); - mitkWidget4Container->setLayout(mitkWidgetLayout4); - - // set SizePolicy - mitkWidget1Container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mitkWidget2Container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mitkWidget3Container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mitkWidget4Container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - // insert Widget Container into the splitters - m_SubSplit1->addWidget(mitkWidget1Container); - m_SubSplit1->addWidget(mitkWidget2Container); - - m_SubSplit2->addWidget(mitkWidget3Container); - m_SubSplit2->addWidget(mitkWidget4Container); - - // Create RenderWindows 1 - mitkWidget1 = new QmitkRenderWindow(mitkWidget1Container, name + ".widget1", nullptr, m_RenderingManager, renderingMode); - mitkWidget1->SetLayoutIndex(AXIAL); - mitkWidgetLayout1->addWidget(mitkWidget1); - - // Create RenderWindows 2 - mitkWidget2 = new QmitkRenderWindow(mitkWidget2Container, name + ".widget2", nullptr, m_RenderingManager, renderingMode); - mitkWidget2->setEnabled(true); - mitkWidget2->SetLayoutIndex(SAGITTAL); - mitkWidgetLayout2->addWidget(mitkWidget2); - - // Create RenderWindows 3 - mitkWidget3 = new QmitkRenderWindow(mitkWidget3Container, name + ".widget3", nullptr, m_RenderingManager, renderingMode); - mitkWidget3->SetLayoutIndex(CORONAL); - mitkWidgetLayout3->addWidget(mitkWidget3); - - // Create RenderWindows 4 - mitkWidget4 = new QmitkRenderWindow(mitkWidget4Container, name + ".widget4", nullptr, m_RenderingManager, renderingMode); - mitkWidget4->SetLayoutIndex(THREE_D); - mitkWidgetLayout4->addWidget(mitkWidget4); - - // create SignalSlot Connection - connect(mitkWidget1, SIGNAL(SignalLayoutDesignChanged(int)), this, SLOT(OnLayoutDesignChanged(int))); - connect(mitkWidget1, SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); - connect(mitkWidget1, SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); - connect(this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget1, SLOT(OnWidgetPlaneModeChanged(int))); - - connect(mitkWidget2, SIGNAL(SignalLayoutDesignChanged(int)), this, SLOT(OnLayoutDesignChanged(int))); - connect(mitkWidget2, SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); - connect(mitkWidget2, SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); - connect(this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget2, SLOT(OnWidgetPlaneModeChanged(int))); - - connect(mitkWidget3, SIGNAL(SignalLayoutDesignChanged(int)), this, SLOT(OnLayoutDesignChanged(int))); - connect(mitkWidget3, SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); - connect(mitkWidget3, SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); - connect(this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget3, SLOT(OnWidgetPlaneModeChanged(int))); - - connect(mitkWidget4, SIGNAL(SignalLayoutDesignChanged(int)), this, SLOT(OnLayoutDesignChanged(int))); - connect(mitkWidget4, SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); - connect(mitkWidget4, SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); - connect(this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget4, SLOT(OnWidgetPlaneModeChanged(int))); - - // Create Level Window Widget - levelWindowWidget = new QmitkLevelWindowWidget(m_MainSplit); // this - levelWindowWidget->setObjectName(QString::fromUtf8("levelWindowWidget")); - QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(levelWindowWidget->sizePolicy().hasHeightForWidth()); - levelWindowWidget->setSizePolicy(sizePolicy); - levelWindowWidget->setMaximumWidth(50); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // resize Image. - this->resize(QSize(364, 477).expandedTo(minimumSizeHint())); - - // Initialize the widgets. - this->InitializeWidget(); - - // Activate Widget Menu - this->ActivateMenuWidget(true); + m_TimeNavigationController = GetRenderingManager()->GetTimeNavigationController(); +} + +QmitkStdMultiWidget::~QmitkStdMultiWidget() +{ + m_TimeNavigationController->Disconnect(GetRenderWindow1()->GetSliceNavigationController()); + m_TimeNavigationController->Disconnect(GetRenderWindow2()->GetSliceNavigationController()); + m_TimeNavigationController->Disconnect(GetRenderWindow3()->GetSliceNavigationController()); + m_TimeNavigationController->Disconnect(GetRenderWindow4()->GetSliceNavigationController()); } -void QmitkStdMultiWidget::InitializeWidget() +void QmitkStdMultiWidget::InitializeMultiWidget() { - // Make all black and overwrite renderwindow 4 - this->FillGradientBackgroundWithBlack(); - // This is #191919 in hex - float tmp1[3] = {0.098f, 0.098f, 0.098f}; - // This is #7F7F7F in hex - float tmp2[3] = {0.498f, 0.498f, 0.498f}; - m_GradientBackgroundColors[3] = std::make_pair(mitk::Color(tmp1), mitk::Color(tmp2)); - - // Yellow is default color for widget4 + // yellow is default color for widget4 m_DecorationColorWidget4[0] = 1.0f; m_DecorationColorWidget4[1] = 1.0f; m_DecorationColorWidget4[2] = 0.0f; + SetLayout(2, 2); + // transfer colors in WorldGeometry-Nodes of the associated Renderer mitk::IntProperty::Pointer layer; // of widget 1 - m_PlaneNode1 = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + m_PlaneNode1 = + mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetColor(GetDecorationColor(0)); layer = mitk::IntProperty::New(1000); m_PlaneNode1->SetProperty("layer", layer); - // ... of widget 2 - m_PlaneNode2 = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + // of widget 2 + m_PlaneNode2 = + mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetColor(GetDecorationColor(1)); layer = mitk::IntProperty::New(1000); m_PlaneNode2->SetProperty("layer", layer); - // ... of widget 3 - m_PlaneNode3 = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + // of widget 3 + m_PlaneNode3 = + mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetColor(GetDecorationColor(2)); layer = mitk::IntProperty::New(1000); m_PlaneNode3->SetProperty("layer", layer); - // The parent node + // the parent node m_ParentNodeForGeometryPlanes = - mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); + mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); layer = mitk::IntProperty::New(1000); m_ParentNodeForGeometryPlanes->SetProperty("layer", layer); - mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); - // Set plane mode (slicing/rotation behavior) to slicing (default) - m_PlaneMode = PLANE_MODE_SLICING; - - // Set default view directions for SNCs - mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); - mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); - mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); - mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); - - SetDecorationProperties("Axial", GetDecorationColor(0), 0); - SetDecorationProperties("Sagittal", GetDecorationColor(1), 1); - SetDecorationProperties("Coronal", GetDecorationColor(2), 2); - SetDecorationProperties("3D", GetDecorationColor(3), 3); - - // connect to the "time navigation controller": send time via sliceNavigationControllers - m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget1->GetSliceNavigationController(), false); - m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget2->GetSliceNavigationController(), false); - m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget3->GetSliceNavigationController(), false); - m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget4->GetSliceNavigationController(), false); - mitkWidget1->GetSliceNavigationController()->ConnectGeometrySendEvent( - mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); - - // reverse connection between sliceNavigationControllers and m_TimeNavigationController - mitkWidget1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); - mitkWidget2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); - mitkWidget3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); - // mitkWidget4->GetSliceNavigationController() - // ->ConnectGeometryTimeEvent(m_TimeNavigationController, false); - - m_MouseModeSwitcher = mitk::MouseModeSwitcher::New(); - - // setup the department logo rendering - m_LogoRendering = mitk::LogoAnnotation::New(); - mitk::BaseRenderer::Pointer renderer4 = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow()); - m_LogoRendering->SetOpacity(0.5); - mitk::Point2D offset; - offset.Fill(0.03); - m_LogoRendering->SetOffsetVector(offset); - m_LogoRendering->SetRelativeSize(0.25); - m_LogoRendering->SetCornerPosition(1); - SetDepartmentLogo(":/org.mitk.gui.qt.stdmultiwidgeteditor/defaultWatermark.png"); - mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_LogoRendering.GetPointer(), renderer4); + AddDisplayPlaneSubTree(); } -void QmitkStdMultiWidget::FillGradientBackgroundWithBlack() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const QString& widgetName) const { - // We have 4 widgets and ... - for (unsigned int i = 0; i < 4; ++i) + if ("axial" == widgetName) { - float black[3] = { 0.0f, 0.0f, 0.0f }; - m_GradientBackgroundColors[i] = std::make_pair(mitk::Color(black), mitk::Color(black)); + return GetRenderWindow1(); } -} -std::pair QmitkStdMultiWidget::GetGradientColors(unsigned int widgetNumber) -{ - if (widgetNumber > 3) + if ("sagittal" == widgetName) { - MITK_ERROR << "Decoration color for unknown widget!"; - float black[3] = { 0.0f, 0.0f, 0.0f }; - return std::make_pair(mitk::Color(black), mitk::Color(black)); + return GetRenderWindow2(); } - return m_GradientBackgroundColors[widgetNumber]; -} -mitk::Color QmitkStdMultiWidget::GetDecorationColor(unsigned int widgetNumber) -{ - // The implementation looks a bit messy here, but it avoids - // synchronization of the color of the geometry nodes and an - // internal member here. - // Default colors were chosen for decent visibitliy. - // Feel free to change your preferences in the workbench. - float tmp[3] = {0.0f, 0.0f, 0.0f}; - switch (widgetNumber) + if ("coronal" == widgetName) { - case 0: - { - if (m_PlaneNode1.IsNotNull()) - { - if (m_PlaneNode1->GetColor(tmp)) - { - return dynamic_cast(m_PlaneNode1->GetProperty("color"))->GetColor(); - } - } - float red[3] = {0.753f, 0.0f, 0.0f}; // This is #C00000 in hex - return mitk::Color(red); - } - case 1: - { - if (m_PlaneNode2.IsNotNull()) - { - if (m_PlaneNode2->GetColor(tmp)) - { - return dynamic_cast(m_PlaneNode2->GetProperty("color"))->GetColor(); - } - } - float green[3] = {0.0f, 0.69f, 0.0f}; // This is #00B000 in hex - return mitk::Color(green); - } - case 2: - { - if (m_PlaneNode3.IsNotNull()) - { - if (m_PlaneNode3->GetColor(tmp)) - { - return dynamic_cast(m_PlaneNode3->GetProperty("color"))->GetColor(); - } - } - float blue[3] = {0.0, 0.502f, 1.0f}; // This is #0080FF in hex - return mitk::Color(blue); - } - case 3: - { - return m_DecorationColorWidget4; - } - default: - MITK_ERROR << "Decoration color for unknown widget!"; - float black[3] = {0.0f, 0.0f, 0.0f}; - return mitk::Color(black); + return GetRenderWindow3(); } -} -std::string QmitkStdMultiWidget::GetCornerAnnotationText(unsigned int widgetNumber) -{ - if (widgetNumber > 3) + if ("3d" == widgetName) { - MITK_ERROR << "Decoration color for unknown widget!"; - return std::string(""); + return GetRenderWindow4(); } - return std::string(m_CornerAnnotations[widgetNumber]->GetText(0)); + + + return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } -QmitkStdMultiWidget::~QmitkStdMultiWidget() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const +{ + return GetRenderWindow(static_cast(viewDirection)); +} + +void QmitkStdMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& /*widgetName*/) { - DisablePositionTracking(); - // DisableNavigationControllerEventListening(); + GetRenderWindow1()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); + GetRenderWindow2()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); + GetRenderWindow3()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); - m_TimeNavigationController->Disconnect(mitkWidget1->GetSliceNavigationController()); - m_TimeNavigationController->Disconnect(mitkWidget2->GetSliceNavigationController()); - m_TimeNavigationController->Disconnect(mitkWidget3->GetSliceNavigationController()); - m_TimeNavigationController->Disconnect(mitkWidget4->GetSliceNavigationController()); + RequestUpdateAll(); } -void QmitkStdMultiWidget::RemovePlanesFromDataStorage() +const mitk::Point3D QmitkStdMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { - if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && - m_ParentNodeForGeometryPlanes.IsNotNull()) + const mitk::PlaneGeometry* plane1 = GetRenderWindow1()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); + const mitk::PlaneGeometry* plane2 = GetRenderWindow2()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); + const mitk::PlaneGeometry* plane3 = GetRenderWindow3()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); + + mitk::Line3D line; + if ((plane1 != nullptr) && (plane2 != nullptr) + && (plane1->IntersectionLine(plane2, line))) { - if (m_DataStorage.IsNotNull()) + mitk::Point3D point; + if ((plane3 != nullptr) && (plane3->IntersectionPoint(line, point))) { - m_DataStorage->Remove(m_PlaneNode1); - m_DataStorage->Remove(m_PlaneNode2); - m_DataStorage->Remove(m_PlaneNode3); - m_DataStorage->Remove(m_ParentNodeForGeometryPlanes); + return point; } } + + return mitk::Point3D(); } -void QmitkStdMultiWidget::AddPlanesToDataStorage() +void QmitkStdMultiWidget::SetCrosshairVisibility(bool visible) { - if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && - m_ParentNodeForGeometryPlanes.IsNotNull()) + if (m_PlaneNode1.IsNotNull()) { - if (m_DataStorage.IsNotNull()) - { - m_DataStorage->Add(m_ParentNodeForGeometryPlanes); - m_DataStorage->Add(m_PlaneNode1, m_ParentNodeForGeometryPlanes); - m_DataStorage->Add(m_PlaneNode2, m_ParentNodeForGeometryPlanes); - m_DataStorage->Add(m_PlaneNode3, m_ParentNodeForGeometryPlanes); - } + m_PlaneNode1->SetVisibility(visible); + } + if (m_PlaneNode2.IsNotNull()) + { + m_PlaneNode2->SetVisibility(visible); + } + if (m_PlaneNode3.IsNotNull()) + { + m_PlaneNode3->SetVisibility(visible); } -} -void QmitkStdMultiWidget::changeLayoutTo2DImagesUp() -{ - SMW_INFO << "changing layout to 2D images up... " << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // Set Layout to widget - this->setLayout(QmitkStdMultiWidgetLayout); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(Qt::Vertical, m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // insert Widget Container into splitter top - m_SubSplit1->addWidget(mitkWidget1Container); - m_SubSplit1->addWidget(mitkWidget2Container); - m_SubSplit1->addWidget(mitkWidget3Container); - - // set SplitterSize for splitter top - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_SubSplit1->setSizes(splitterSize); - - // insert Widget Container into splitter bottom - m_SubSplit2->addWidget(mitkWidget4Container); - - // set SplitterSize for splitter m_LayoutSplit - splitterSize.clear(); - splitterSize.push_back(400); - splitterSize.push_back(1000); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt - m_MainSplit->show(); - - // show Widget if hidden - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - // Change Layout Name - m_Layout = LAYOUT_2D_IMAGES_UP; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_2D_IMAGES_UP); - mitkWidget2->LayoutDesignListChanged(LAYOUT_2D_IMAGES_UP); - mitkWidget3->LayoutDesignListChanged(LAYOUT_2D_IMAGES_UP); - mitkWidget4->LayoutDesignListChanged(LAYOUT_2D_IMAGES_UP); - - // update Alle Widgets - this->UpdateAllWidgets(); + RequestUpdateAll(); } -void QmitkStdMultiWidget::changeLayoutTo2DImagesLeft() +bool QmitkStdMultiWidget::GetCrosshairVisibility() const { - SMW_INFO << "changing layout to 2D images left... " << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(Qt::Vertical, m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // insert Widget into the splitters - m_SubSplit1->addWidget(mitkWidget1Container); - m_SubSplit1->addWidget(mitkWidget2Container); - m_SubSplit1->addWidget(mitkWidget3Container); - - // set splitterSize of SubSplit1 - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_SubSplit1->setSizes(splitterSize); - - m_SubSplit2->addWidget(mitkWidget4Container); - - // set splitterSize of Layout Split - splitterSize.clear(); - splitterSize.push_back(400); - splitterSize.push_back(1000); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show Widget if hidden - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - // update Layout Name - m_Layout = LAYOUT_2D_IMAGES_LEFT; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_2D_IMAGES_LEFT); - mitkWidget2->LayoutDesignListChanged(LAYOUT_2D_IMAGES_LEFT); - mitkWidget3->LayoutDesignListChanged(LAYOUT_2D_IMAGES_LEFT); - mitkWidget4->LayoutDesignListChanged(LAYOUT_2D_IMAGES_LEFT); - - // update Alle Widgets - this->UpdateAllWidgets(); -} + bool crosshairVisibility = true; -void QmitkStdMultiWidget::SetDecorationProperties(std::string text, mitk::Color color, int widgetNumber) -{ - if (widgetNumber > 3) + if (m_PlaneNode1.IsNotNull()) { - MITK_ERROR << "Unknown render window for annotation."; - return; + bool visibilityProperty = false; + m_PlaneNode1->GetVisibility(visibilityProperty, nullptr); + crosshairVisibility &= visibilityProperty; } - vtkRenderer *renderer = this->GetRenderWindow(widgetNumber)->GetRenderer()->GetVtkRenderer(); - if (!renderer) - return; - vtkSmartPointer annotation = m_CornerAnnotations[widgetNumber]; - annotation->SetText(0, text.c_str()); - annotation->SetMaximumFontSize(12); - annotation->GetTextProperty()->SetColor(color[0], color[1], color[2]); - if (!renderer->HasViewProp(annotation)) + + if (m_PlaneNode2.IsNotNull()) { - renderer->AddViewProp(annotation); + bool visibilityProperty = false; + crosshairVisibility &= m_PlaneNode2->GetVisibility(visibilityProperty, nullptr); + crosshairVisibility &= visibilityProperty; } - vtkSmartPointer frame = m_RectangleProps[widgetNumber]; - frame->SetColor(color[0], color[1], color[2]); - if (!renderer->HasViewProp(frame)) + + if (m_PlaneNode3.IsNotNull()) { - renderer->AddViewProp(frame); + bool visibilityProperty = false; + crosshairVisibility &= m_PlaneNode3->GetVisibility(visibilityProperty, nullptr); + crosshairVisibility &= visibilityProperty; } + + return crosshairVisibility; } -void QmitkStdMultiWidget::SetCornerAnnotationVisibility(bool visibility) +void QmitkStdMultiWidget::ResetCrosshair() { - for (int i = 0; i < 4; ++i) + auto dataStorage = GetDataStorage(); + if (nullptr == dataStorage) { - m_CornerAnnotations[i]->SetVisibility(visibility); + return; } -} -bool QmitkStdMultiWidget::IsCornerAnnotationVisible(void) const -{ - return m_CornerAnnotations[0]->GetVisibility() > 0; + GetRenderingManager()->InitializeViewsByBoundingObjects(dataStorage); + + SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } -QmitkRenderWindow *QmitkStdMultiWidget::GetRenderWindow(unsigned int number) +void QmitkStdMultiWidget::SetWidgetPlaneMode(int userMode) { - switch (number) + MITK_DEBUG << "Changing crosshair mode to " << userMode; + + switch (userMode) { - case 0: - return this->GetRenderWindow1(); - case 1: - return this->GetRenderWindow2(); - case 2: - return this->GetRenderWindow3(); - case 3: - return this->GetRenderWindow4(); - default: - MITK_ERROR << "Requested unknown render window"; - break; + case 0: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); + break; + case 1: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); + break; + case 2: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); + break; + case 3: + SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); + break; } - return nullptr; } -void QmitkStdMultiWidget::changeLayoutToDefault() +mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { - SMW_INFO << "changing layout to default... " << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(Qt::Vertical, m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // insert Widget container into the splitters - m_SubSplit1->addWidget(mitkWidget1Container); - m_SubSplit1->addWidget(mitkWidget2Container); - - m_SubSplit2->addWidget(mitkWidget3Container); - m_SubSplit2->addWidget(mitkWidget4Container); - - // set splitter Size - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_SubSplit1->setSizes(splitterSize); - m_SubSplit2->setSizes(splitterSize); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show Widget if hidden - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_DEFAULT; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_DEFAULT); - mitkWidget2->LayoutDesignListChanged(LAYOUT_DEFAULT); - mitkWidget3->LayoutDesignListChanged(LAYOUT_DEFAULT); - mitkWidget4->LayoutDesignListChanged(LAYOUT_DEFAULT); - - // update Alle Widgets - this->UpdateAllWidgets(); + return m_TimeNavigationController; } -void QmitkStdMultiWidget::changeLayoutToBig3D() +void QmitkStdMultiWidget::AddPlanesToDataStorage() { - SMW_INFO << "changing layout to big 3D ..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // add widget Splitter to main Splitter - m_MainSplit->addWidget(mitkWidget4Container); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - mitkWidget1->hide(); - mitkWidget2->hide(); - mitkWidget3->hide(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_BIG_3D; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_BIG_3D); - mitkWidget2->LayoutDesignListChanged(LAYOUT_BIG_3D); - mitkWidget3->LayoutDesignListChanged(LAYOUT_BIG_3D); - mitkWidget4->LayoutDesignListChanged(LAYOUT_BIG_3D); + auto dataStorage = GetDataStorage(); + if (nullptr == dataStorage) + { + return; + } - // update Alle Widgets - this->UpdateAllWidgets(); - mitk::RenderingManager::GetInstance()->SetRenderWindowFocus(mitkWidget4->GetVtkRenderWindow()); + if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() + && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) + { + dataStorage->Add(m_ParentNodeForGeometryPlanes); + dataStorage->Add(m_PlaneNode1, m_ParentNodeForGeometryPlanes); + dataStorage->Add(m_PlaneNode2, m_ParentNodeForGeometryPlanes); + dataStorage->Add(m_PlaneNode3, m_ParentNodeForGeometryPlanes); + } } -void QmitkStdMultiWidget::changeLayoutToWidget1() +void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { - SMW_INFO << "changing layout to big Widget1 ..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // add widget Splitter to main Splitter - m_MainSplit->addWidget(mitkWidget1Container); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - mitkWidget2->hide(); - mitkWidget3->hide(); - mitkWidget4->hide(); - - m_Layout = LAYOUT_WIDGET1; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_WIDGET1); - mitkWidget2->LayoutDesignListChanged(LAYOUT_WIDGET1); - mitkWidget3->LayoutDesignListChanged(LAYOUT_WIDGET1); - mitkWidget4->LayoutDesignListChanged(LAYOUT_WIDGET1); - - // update Alle Widgets - this->UpdateAllWidgets(); + auto dataStorage = GetDataStorage(); + if (nullptr == dataStorage) + { + return; + } - mitk::RenderingManager::GetInstance()->SetRenderWindowFocus(mitkWidget1->GetVtkRenderWindow()); + if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() + && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) + { + dataStorage->Remove(m_PlaneNode1); + dataStorage->Remove(m_PlaneNode2); + dataStorage->Remove(m_PlaneNode3); + dataStorage->Remove(m_ParentNodeForGeometryPlanes); + } } -void QmitkStdMultiWidget::changeLayoutToWidget2() +void QmitkStdMultiWidget::HandleCrosshairPositionEvent() { - SMW_INFO << "changing layout to big Widget2 ..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // add widget Splitter to main Splitter - m_MainSplit->addWidget(mitkWidget2Container); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - mitkWidget1->hide(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - mitkWidget3->hide(); - mitkWidget4->hide(); - - m_Layout = LAYOUT_WIDGET2; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_WIDGET2); - mitkWidget2->LayoutDesignListChanged(LAYOUT_WIDGET2); - mitkWidget3->LayoutDesignListChanged(LAYOUT_WIDGET2); - mitkWidget4->LayoutDesignListChanged(LAYOUT_WIDGET2); - - // update Alle Widgets - this->UpdateAllWidgets(); - mitk::RenderingManager::GetInstance()->SetRenderWindowFocus(mitkWidget2->GetVtkRenderWindow()); + if (!m_PendingCrosshairPositionEvent) + { + m_PendingCrosshairPositionEvent = true; + QTimer::singleShot(0, this, SLOT(HandleCrosshairPositionEventDelayed())); + } } -void QmitkStdMultiWidget::changeLayoutToWidget3() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(unsigned int number) const { - SMW_INFO << "changing layout to big Widget3 ..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // add widget Splitter to main Splitter - m_MainSplit->addWidget(mitkWidget3Container); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - mitkWidget1->hide(); - mitkWidget2->hide(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - mitkWidget4->hide(); - - m_Layout = LAYOUT_WIDGET3; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_WIDGET3); - mitkWidget2->LayoutDesignListChanged(LAYOUT_WIDGET3); - mitkWidget3->LayoutDesignListChanged(LAYOUT_WIDGET3); - mitkWidget4->LayoutDesignListChanged(LAYOUT_WIDGET3); + switch (number) + { + case 0: + return GetRenderWindow1(); + case 1: + return GetRenderWindow2(); + case 2: + return GetRenderWindow3(); + case 3: + return GetRenderWindow4(); + default: + MITK_ERROR << "Requested unknown render window"; + break; + } - // update Alle Widgets - this->UpdateAllWidgets(); - mitk::RenderingManager::GetInstance()->SetRenderWindowFocus(mitkWidget3->GetVtkRenderWindow()); + return nullptr; } -void QmitkStdMultiWidget::changeLayoutToRowWidget3And4() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { - SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(Qt::Vertical, m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // add Widgets to splitter - m_LayoutSplit->addWidget(mitkWidget3Container); - m_LayoutSplit->addWidget(mitkWidget4Container); - - // set Splitter Size - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - mitkWidget1->hide(); - mitkWidget2->hide(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_ROW_WIDGET_3_AND_4; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_ROW_WIDGET_3_AND_4); - mitkWidget2->LayoutDesignListChanged(LAYOUT_ROW_WIDGET_3_AND_4); - mitkWidget3->LayoutDesignListChanged(LAYOUT_ROW_WIDGET_3_AND_4); - mitkWidget4->LayoutDesignListChanged(LAYOUT_ROW_WIDGET_3_AND_4); - - // update Alle Widgets - this->UpdateAllWidgets(); + return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 0)); } -void QmitkStdMultiWidget::changeLayoutToColumnWidget3And4() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { - SMW_INFO << "changing layout to Widget3 and 4 in one Column..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // add Widgets to splitter - m_LayoutSplit->addWidget(mitkWidget3Container); - m_LayoutSplit->addWidget(mitkWidget4Container); - - // set SplitterSize - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - mitkWidget1->hide(); - mitkWidget2->hide(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_COLUMN_WIDGET_3_AND_4; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_COLUMN_WIDGET_3_AND_4); - mitkWidget2->LayoutDesignListChanged(LAYOUT_COLUMN_WIDGET_3_AND_4); - mitkWidget3->LayoutDesignListChanged(LAYOUT_COLUMN_WIDGET_3_AND_4); - mitkWidget4->LayoutDesignListChanged(LAYOUT_COLUMN_WIDGET_3_AND_4); - - // update Alle Widgets - this->UpdateAllWidgets(); + return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 1)); } -void QmitkStdMultiWidget::changeLayoutToRowWidgetSmall3andBig4() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { - SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; - - this->changeLayoutToRowWidget3And4(); - - m_Layout = LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4; + return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 0)); } -void QmitkStdMultiWidget::changeLayoutToSmallUpperWidget2Big3and4() +QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { - SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(Qt::Vertical, m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(Qt::Vertical, m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // insert Widget into the splitters - m_SubSplit1->addWidget(mitkWidget2Container); - - m_SubSplit2->addWidget(mitkWidget3Container); - m_SubSplit2->addWidget(mitkWidget4Container); - - // set Splitter Size - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_SubSplit2->setSizes(splitterSize); - splitterSize.clear(); - splitterSize.push_back(500); - splitterSize.push_back(1000); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt - m_MainSplit->show(); - - // show Widget if hidden - mitkWidget1->hide(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4); - mitkWidget2->LayoutDesignListChanged(LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4); - mitkWidget3->LayoutDesignListChanged(LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4); - mitkWidget4->LayoutDesignListChanged(LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4); - - // update Alle Widgets - this->UpdateAllWidgets(); + return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 1)); } -void QmitkStdMultiWidget::changeLayoutTo2x2Dand3DWidget() +mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() const { - SMW_INFO << "changing layout to 2 x 2D and 3D Widget" << std::endl; - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(Qt::Vertical, m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // add Widgets to splitter - m_SubSplit1->addWidget(mitkWidget1Container); - m_SubSplit1->addWidget(mitkWidget2Container); - m_SubSplit2->addWidget(mitkWidget4Container); - - // set Splitter Size - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_SubSplit1->setSizes(splitterSize); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - mitkWidget3->hide(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_2X_2D_AND_3D_WIDGET; + return m_PlaneNode1; +} - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_2X_2D_AND_3D_WIDGET); - mitkWidget2->LayoutDesignListChanged(LAYOUT_2X_2D_AND_3D_WIDGET); - mitkWidget3->LayoutDesignListChanged(LAYOUT_2X_2D_AND_3D_WIDGET); - mitkWidget4->LayoutDesignListChanged(LAYOUT_2X_2D_AND_3D_WIDGET); +mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() const +{ + return m_PlaneNode2; +} - // update Alle Widgets - this->UpdateAllWidgets(); +mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() const +{ + return m_PlaneNode3; } -void QmitkStdMultiWidget::changeLayoutToLeft2Dand3DRight2D() +mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(unsigned number) const { - SMW_INFO << "changing layout to 2D and 3D left, 2D right Widget" << std::endl; + switch (number) + { + case 1: + return m_PlaneNode1; + case 2: + return m_PlaneNode2; + case 3: + return m_PlaneNode3; + default: + MITK_ERROR << "Requested unknown render window"; + break; + } - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); + return nullptr; +} - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(Qt::Vertical, m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // add Widgets to splitter - m_SubSplit1->addWidget(mitkWidget1Container); - m_SubSplit1->addWidget(mitkWidget4Container); - m_SubSplit2->addWidget(mitkWidget2Container); - - // set Splitter Size - QList splitterSize; - splitterSize.push_back(1000); - splitterSize.push_back(1000); - m_SubSplit1->setSizes(splitterSize); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt and add to Layout - m_MainSplit->show(); - - // show/hide Widgets - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - mitkWidget3->hide(); - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET); - mitkWidget2->LayoutDesignListChanged(LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET); - mitkWidget3->LayoutDesignListChanged(LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET); - mitkWidget4->LayoutDesignListChanged(LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET); - - // update Alle Widgets - this->UpdateAllWidgets(); -} - -void QmitkStdMultiWidget::changeLayoutTo2DUpAnd3DDown(unsigned int id2Dwindow) +void QmitkStdMultiWidget::SetDecorationColor(unsigned int widgetNumber, mitk::Color color) { - SMW_INFO << "changing layout to 2D up and 3D down" << std::endl; - if (id2Dwindow < 1 || id2Dwindow > 3) - { - MITK_WARN << "Only 2D render window IDs 1,2 or 3 are valid. Got ID " << id2Dwindow << ". " << "Using default ID 2 instead."; - id2Dwindow = 2; - } - - // Hide all Menu Widgets - this->HideAllWidgetToolbars(); - - delete QmitkStdMultiWidgetLayout; - - // create Main Layout - QmitkStdMultiWidgetLayout = new QHBoxLayout(this); - - // Set Layout to widget - this->setLayout(QmitkStdMultiWidgetLayout); - - // create main splitter - m_MainSplit = new QSplitter(this); - QmitkStdMultiWidgetLayout->addWidget(m_MainSplit); - - // create m_LayoutSplit and add to the mainSplit - m_LayoutSplit = new QSplitter(Qt::Vertical, m_MainSplit); - m_MainSplit->addWidget(m_LayoutSplit); - - // add LevelWindow Widget to mainSplitter - m_MainSplit->addWidget(levelWindowWidget); - - // create m_SubSplit1 and m_SubSplit2 - m_SubSplit1 = new QSplitter(m_LayoutSplit); - m_SubSplit2 = new QSplitter(m_LayoutSplit); - - // insert Widget Container into splitter top - switch (id2Dwindow) + switch (widgetNumber) { + case 0: + if (m_PlaneNode1.IsNotNull()) + { + m_PlaneNode1->SetColor(color); + } + break; case 1: - m_SubSplit1->addWidget(mitkWidget1Container); + if (m_PlaneNode2.IsNotNull()) + { + m_PlaneNode2->SetColor(color); + } break; case 2: - m_SubSplit1->addWidget(mitkWidget2Container); + if (m_PlaneNode3.IsNotNull()) + { + m_PlaneNode3->SetColor(color); + } break; case 3: - m_SubSplit1->addWidget(mitkWidget3Container); + m_DecorationColorWidget4 = color; + break; + default: + MITK_ERROR << "Decoration color for unknown widget!"; break; } +} - // set SplitterSize for splitter top - QList splitterSize; - // insert Widget Container into splitter bottom - m_SubSplit2->addWidget(mitkWidget4Container); - // set SplitterSize for splitter m_LayoutSplit - splitterSize.clear(); - splitterSize.push_back(700); - splitterSize.push_back(700); - m_LayoutSplit->setSizes(splitterSize); - - // show mainSplitt - m_MainSplit->show(); - - // show/hide Widgets - switch (id2Dwindow) +mitk::Color QmitkStdMultiWidget::GetDecorationColor(unsigned int widgetNumber) +{ + // The implementation looks a bit messy here, but it avoids + // synchronization of the color of the geometry nodes and an + // internal member here. + // Default colors were chosen for decent visibility. + // Feel free to change your preferences in the workbench. + float tmp[3] = { 0.0f, 0.0f, 0.0f }; + switch (widgetNumber) + { + case 0: { + if (m_PlaneNode1.IsNotNull()) + { + if (m_PlaneNode1->GetColor(tmp)) + { + return dynamic_cast(m_PlaneNode1->GetProperty("color"))->GetColor(); + } + } + float red[3] = { 0.753f, 0.0f, 0.0f }; // This is #C00000 in hex + return mitk::Color(red); + } case 1: - if (mitkWidget1->isHidden()) - mitkWidget1->show(); - mitkWidget2->hide(); - mitkWidget3->hide(); - break; + { + if (m_PlaneNode2.IsNotNull()) + { + if (m_PlaneNode2->GetColor(tmp)) + { + return dynamic_cast(m_PlaneNode2->GetProperty("color"))->GetColor(); + } + } + float green[3] = { 0.0f, 0.69f, 0.0f }; // This is #00B000 in hex + return mitk::Color(green); + } case 2: - if (mitkWidget2->isHidden()) - mitkWidget2->show(); - mitkWidget1->hide(); - mitkWidget3->hide(); - break; + { + if (m_PlaneNode3.IsNotNull()) + { + if (m_PlaneNode3->GetColor(tmp)) + { + return dynamic_cast(m_PlaneNode3->GetProperty("color"))->GetColor(); + } + } + float blue[3] = { 0.0, 0.502f, 1.0f }; // This is #0080FF in hex + return mitk::Color(blue); + } case 3: - if (mitkWidget3->isHidden()) - mitkWidget3->show(); - mitkWidget1->hide(); - mitkWidget2->hide(); - break; + { + return m_DecorationColorWidget4; + } + default: + MITK_ERROR << "Decoration color for unknown widget!"; + float black[3] = { 0.0f, 0.0f, 0.0f }; + return mitk::Color(black); } - - //always show 3D widget - if (mitkWidget4->isHidden()) - mitkWidget4->show(); - - m_Layout = LAYOUT_2D_UP_AND_3D_DOWN; - - // update Layout Design List - mitkWidget1->LayoutDesignListChanged(LAYOUT_2D_UP_AND_3D_DOWN); - mitkWidget2->LayoutDesignListChanged(LAYOUT_2D_UP_AND_3D_DOWN); - mitkWidget3->LayoutDesignListChanged(LAYOUT_2D_UP_AND_3D_DOWN); - mitkWidget4->LayoutDesignListChanged(LAYOUT_2D_UP_AND_3D_DOWN); - - // update all Widgets - this->UpdateAllWidgets(); } -void QmitkStdMultiWidget::SetDataStorage(mitk::DataStorage *ds) +void QmitkStdMultiWidget::mousePressEvent(QMouseEvent* e) { - if (ds == m_DataStorage) + if (QEvent::MouseButtonPress != e->type()) { return; } - mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->SetDataStorage(ds); - mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->SetDataStorage(ds); - mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->SetDataStorage(ds); - mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->SetDataStorage(ds); - m_DataStorage = ds; -} - -void QmitkStdMultiWidget::Fit() -{ - vtkSmartPointer vtkrenderer; - vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetVtkRenderer(); - if (vtkrenderer != nullptr) - vtkrenderer->ResetCamera(); - - vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetVtkRenderer(); - if (vtkrenderer != nullptr) - vtkrenderer->ResetCamera(); - - vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetVtkRenderer(); - if (vtkrenderer != nullptr) - vtkrenderer->ResetCamera(); - - vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetVtkRenderer(); - if (vtkrenderer != nullptr) - vtkrenderer->ResetCamera(); - - mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetCameraController()->Fit(); - mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetCameraController()->Fit(); - mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetCameraController()->Fit(); - mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetCameraController()->Fit(); - - int w = vtkObject::GetGlobalWarningDisplay(); - vtkObject::GlobalWarningDisplayOff(); - - vtkObject::SetGlobalWarningDisplay(w); -} - -void QmitkStdMultiWidget::InitPositionTracking() -{ - // TODO POSITIONTRACKER -} - -void QmitkStdMultiWidget::AddDisplayPlaneSubTree() -{ - // add the displayed planes of the multiwidget to a node to which the subtree - // @a planesSubTree points ... - - mitk::PlaneGeometryDataMapper2D::Pointer mapper; - - // ... of widget 1 - mitk::BaseRenderer *renderer1 = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()); - m_PlaneNode1 = renderer1->GetCurrentWorldPlaneGeometryNode(); - m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); - m_PlaneNode1->SetProperty("name", mitk::StringProperty::New(std::string(renderer1->GetName()) + ".plane")); - m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); - m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); - mapper = mitk::PlaneGeometryDataMapper2D::New(); - m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); - - // ... of widget 2 - mitk::BaseRenderer *renderer2 = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow()); - m_PlaneNode2 = renderer2->GetCurrentWorldPlaneGeometryNode(); - m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); - m_PlaneNode2->SetProperty("name", mitk::StringProperty::New(std::string(renderer2->GetName()) + ".plane")); - m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); - m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); - mapper = mitk::PlaneGeometryDataMapper2D::New(); - m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); - - // ... of widget 3 - mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow()); - m_PlaneNode3 = renderer3->GetCurrentWorldPlaneGeometryNode(); - m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); - m_PlaneNode3->SetProperty("name", mitk::StringProperty::New(std::string(renderer3->GetName()) + ".plane")); - m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); - m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); - mapper = mitk::PlaneGeometryDataMapper2D::New(); - m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); - - m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); - m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New("Widgets")); - m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); -} - -mitk::SliceNavigationController *QmitkStdMultiWidget::GetTimeNavigationController() -{ - return m_TimeNavigationController; -} - -void QmitkStdMultiWidget::EnableStandardLevelWindow() -{ - levelWindowWidget->disconnect(this); - levelWindowWidget->SetDataStorage(mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetDataStorage()); - levelWindowWidget->show(); -} - -void QmitkStdMultiWidget::DisableStandardLevelWindow() -{ - levelWindowWidget->disconnect(this); - levelWindowWidget->hide(); -} - -// CAUTION: Legacy code for enabling Qt-signal-controlled view initialization. -// Use RenderingManager::InitializeViews() instead. -bool QmitkStdMultiWidget::InitializeStandardViews(const mitk::Geometry3D *geometry) -{ - return m_RenderingManager->InitializeViews(geometry); -} - -void QmitkStdMultiWidget::RequestUpdate() -{ - m_RenderingManager->RequestUpdate(mitkWidget1->GetRenderWindow()); - m_RenderingManager->RequestUpdate(mitkWidget2->GetRenderWindow()); - m_RenderingManager->RequestUpdate(mitkWidget3->GetRenderWindow()); - m_RenderingManager->RequestUpdate(mitkWidget4->GetRenderWindow()); -} - -void QmitkStdMultiWidget::ForceImmediateUpdate() -{ - m_RenderingManager->ForceImmediateUpdate(mitkWidget1->GetRenderWindow()); - m_RenderingManager->ForceImmediateUpdate(mitkWidget2->GetRenderWindow()); - m_RenderingManager->ForceImmediateUpdate(mitkWidget3->GetRenderWindow()); - m_RenderingManager->ForceImmediateUpdate(mitkWidget4->GetRenderWindow()); -} - -void QmitkStdMultiWidget::wheelEvent(QWheelEvent *e) -{ - emit WheelMoved(e); -} + auto renderWindowWidget = dynamic_cast(this->sender()); + if (nullptr == renderWindowWidget) + { + return; + } -void QmitkStdMultiWidget::mousePressEvent(QMouseEvent *) -{ + auto renderWindowWidgetPointer = GetRenderWindowWidget(renderWindowWidget->GetWidgetName()); + SetActiveRenderWindowWidget(renderWindowWidgetPointer); } -void QmitkStdMultiWidget::moveEvent(QMoveEvent *e) +void QmitkStdMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the Annotation as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } -QmitkRenderWindow *QmitkStdMultiWidget::GetRenderWindow1() const -{ - return mitkWidget1; -} - -QmitkRenderWindow *QmitkStdMultiWidget::GetRenderWindow2() const -{ - return mitkWidget2; -} - -QmitkRenderWindow *QmitkStdMultiWidget::GetRenderWindow3() const -{ - return mitkWidget3; -} - -QmitkRenderWindow *QmitkStdMultiWidget::GetRenderWindow4() const -{ - return mitkWidget4; -} - -const mitk::Point3D QmitkStdMultiWidget::GetCrossPosition() const +void QmitkStdMultiWidget::wheelEvent(QWheelEvent* e) { - const mitk::PlaneGeometry *plane1 = mitkWidget1->GetSliceNavigationController()->GetCurrentPlaneGeometry(); - const mitk::PlaneGeometry *plane2 = mitkWidget2->GetSliceNavigationController()->GetCurrentPlaneGeometry(); - const mitk::PlaneGeometry *plane3 = mitkWidget3->GetSliceNavigationController()->GetCurrentPlaneGeometry(); - - mitk::Line3D line; - if ((plane1 != nullptr) && (plane2 != nullptr) && (plane1->IntersectionLine(plane2, line))) - { - mitk::Point3D point; - if ((plane3 != nullptr) && (plane3->IntersectionPoint(line, point))) - { - return point; - } - } - // TODO BUG POSITIONTRACKER; - mitk::Point3D p; - return p; - // return m_LastLeftClickPositionSupplier->GetCurrentPoint(); -} - -void QmitkStdMultiWidget::EnablePositionTracking() -{ -} - -void QmitkStdMultiWidget::DisablePositionTracking() -{ -} - -void QmitkStdMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) -{ - mitk::Point2D pointOnDisplay; - renderer->WorldToDisplay(p, pointOnDisplay); - - if (pointOnDisplay[0] < renderer->GetVtkRenderer()->GetOrigin()[0] || - pointOnDisplay[1] < renderer->GetVtkRenderer()->GetOrigin()[1] || - pointOnDisplay[0] > renderer->GetVtkRenderer()->GetOrigin()[0] + renderer->GetViewportSize()[0] || - pointOnDisplay[1] > renderer->GetVtkRenderer()->GetOrigin()[1] + renderer->GetViewportSize()[1]) - { - mitk::Point2D pointOnPlane; - renderer->GetCurrentWorldPlaneGeometry()->Map(p, pointOnPlane); - renderer->GetCameraController()->MoveCameraToPoint(pointOnPlane); - } -} - -void QmitkStdMultiWidget::MoveCrossToPosition(const mitk::Point3D &newPosition) -{ - mitkWidget1->GetSliceNavigationController()->SelectSliceByPoint(newPosition); - mitkWidget2->GetSliceNavigationController()->SelectSliceByPoint(newPosition); - mitkWidget3->GetSliceNavigationController()->SelectSliceByPoint(newPosition); - - m_RenderingManager->RequestUpdateAll(); + emit WheelMoved(e); } -void QmitkStdMultiWidget::HandleCrosshairPositionEvent() +void QmitkStdMultiWidget::HandleCrosshairPositionEventDelayed() { - if (!m_PendingCrosshairPositionEvent) + auto dataStorage = GetDataStorage(); + if (nullptr == dataStorage) { - m_PendingCrosshairPositionEvent = true; - QTimer::singleShot(0, this, SLOT(HandleCrosshairPositionEventDelayed())); + return; } -} -void QmitkStdMultiWidget::HandleCrosshairPositionEventDelayed() -{ m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); - mitk::DataStorage::SetOfObjects::ConstPointer nodes = m_DataStorage->GetSubset(isImageData).GetPointer(); - mitk::Point3D crosshairPos = GetCrossPosition(); - mitk::BaseRenderer* baseRenderer = mitkWidget1->GetSliceNavigationController()->GetRenderer(); + mitk::DataStorage::SetOfObjects::ConstPointer nodes = dataStorage->GetSubset(isImageData).GetPointer(); + mitk::Point3D crosshairPos = GetSelectedPosition(""); + mitk::BaseRenderer* baseRenderer = GetRenderWindow1()->GetSliceNavigationController()->GetRenderer(); auto globalCurrentTimePoint = baseRenderer->GetTime(); mitk::DataNode::Pointer node = mitk::FindTopmostVisibleNode(nodes, crosshairPos, globalCurrentTimePoint, baseRenderer); mitk::DataNode::Pointer topSourceNode; mitk::Image::Pointer image; bool isBinary = false; int component = 0; if (node.IsNotNull()) { node->GetBoolProperty("binary", isBinary); if (isBinary) { - mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = m_DataStorage->GetSources(node, nullptr, true); + mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = dataStorage->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { - topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, crosshairPos,globalCurrentTimePoint, baseRenderer); + topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, crosshairPos, globalCurrentTimePoint, baseRenderer); } if (topSourceNode.IsNotNull()) { image = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } std::string statusText; std::stringstream stream; itk::Index<3> p; unsigned int timestep = baseRenderer->GetTimeStep(); if (image.IsNotNull() && (image->GetTimeSteps() > timestep)) { image->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream << "Position: <" << std::fixed << crosshairPos[0] << ", " << std::fixed << crosshairPos[1] << ", " - << std::fixed << crosshairPos[2] << "> mm"; + << std::fixed << crosshairPos[2] << "> mm"; stream << "; Index: <" << p[0] << ", " << p[1] << ", " << p[2] << "> "; mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, - image->GetChannelDescriptor().GetPixelType(), - image, - image->GetVolumeData(image->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), - p, - pixelValue, - component); + image->GetChannelDescriptor().GetPixelType(), + image, + image->GetVolumeData(image->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), + p, + pixelValue, + component); if (fabs(pixelValue) > 1000000 || fabs(pixelValue) < 0.01) { - stream << "; Time: " <DisplayGreyValueText(statusText.c_str()); } -int QmitkStdMultiWidget::GetLayout() const -{ - return m_Layout; -} - -bool QmitkStdMultiWidget::GetGradientBackgroundFlag() const -{ - return m_GradientBackgroundFlag; -} - -void QmitkStdMultiWidget::EnableGradientBackground() +void QmitkStdMultiWidget::Fit() { - // gradient background is by default only in widget 4, otherwise - // interferences between 2D rendering and VTK rendering may occur. - for (unsigned int i = 0; i < 4; ++i) + vtkSmartPointer vtkrenderer; + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetVtkRenderer(); + if (nullptr != vtkrenderer) { - GetRenderWindow(i)->GetRenderer()->GetVtkRenderer()->GradientBackgroundOn(); + vtkrenderer->ResetCamera(); } - m_GradientBackgroundFlag = true; -} -void QmitkStdMultiWidget::DisableGradientBackground() -{ - for (unsigned int i = 0; i < 4; ++i) + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetVtkRenderer(); + if (nullptr != vtkrenderer) { - GetRenderWindow(i)->GetRenderer()->GetVtkRenderer()->GradientBackgroundOff(); + vtkrenderer->ResetCamera(); } - m_GradientBackgroundFlag = false; -} - -void QmitkStdMultiWidget::EnableDepartmentLogo() -{ - m_LogoRendering->SetVisibility(true); - RequestUpdate(); -} - -void QmitkStdMultiWidget::DisableDepartmentLogo() -{ - m_LogoRendering->SetVisibility(false); - RequestUpdate(); -} - -bool QmitkStdMultiWidget::IsDepartmentLogoEnabled() const -{ - return m_LogoRendering->IsVisible(); -} -void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer) -{ - if (m_DataStorage.IsNotNull()) + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetVtkRenderer(); + if (nullptr != vtkrenderer) { - mitk::DataNode *n = m_DataStorage->GetNamedNode(widgetName); - if (n != nullptr) - n->SetVisibility(visible, renderer); + vtkrenderer->ResetCamera(); } -} -void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) -{ - if (m_PlaneNode1.IsNotNull()) - { - m_PlaneNode1->SetVisibility(visible, renderer); - } - if (m_PlaneNode2.IsNotNull()) + vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetVtkRenderer(); + if (nullptr != vtkrenderer) { - m_PlaneNode2->SetVisibility(visible, renderer); - } - if (m_PlaneNode3.IsNotNull()) - { - m_PlaneNode3->SetVisibility(visible, renderer); + vtkrenderer->ResetCamera(); } - m_RenderingManager->RequestUpdateAll(); -} - -void QmitkStdMultiWidget::SetWidgetPlanesLocked(bool locked) -{ - // do your job and lock or unlock slices. - GetRenderWindow1()->GetSliceNavigationController()->SetSliceLocked(locked); - GetRenderWindow2()->GetSliceNavigationController()->SetSliceLocked(locked); - GetRenderWindow3()->GetSliceNavigationController()->SetSliceLocked(locked); -} - -void QmitkStdMultiWidget::SetWidgetPlanesRotationLocked(bool locked) -{ - // do your job and lock or unlock slices. - GetRenderWindow1()->GetSliceNavigationController()->SetSliceRotationLocked(locked); - GetRenderWindow2()->GetSliceNavigationController()->SetSliceRotationLocked(locked); - GetRenderWindow3()->GetSliceNavigationController()->SetSliceRotationLocked(locked); -} -void QmitkStdMultiWidget::SetWidgetPlanesRotationLinked(bool link) -{ - emit WidgetPlanesRotationLinked(link); -} + mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetCameraController()->Fit(); + mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetCameraController()->Fit(); -void QmitkStdMultiWidget::SetWidgetPlaneMode(int userMode) -{ - MITK_DEBUG << "Changing crosshair mode to " << userMode; + int w = vtkObject::GetGlobalWarningDisplay(); + vtkObject::GlobalWarningDisplayOff(); - emit WidgetNotifyNewCrossHairMode(userMode); - // Convert user interface mode to actual mode - { - switch (userMode) - { - case 0: - m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::MITK); - break; - case 1: - m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::ROTATION); - break; - - case 2: - m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::ROTATIONLINKED); - break; - - case 3: - m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::SWIVEL); - break; - } - } + vtkObject::SetGlobalWarningDisplay(w); } -void QmitkStdMultiWidget::SetGradientBackgroundColorForRenderWindow(const mitk::Color &upper, - const mitk::Color &lower, - unsigned int widgetNumber) +void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { - if (widgetNumber > 3) - { - MITK_ERROR << "Gradientbackground for unknown widget!"; - return; - } - m_GradientBackgroundColors[widgetNumber].first = upper; - m_GradientBackgroundColors[widgetNumber].second = lower; - vtkRenderer *renderer = GetRenderWindow(widgetNumber)->GetRenderer()->GetVtkRenderer(); - renderer->SetBackground2(upper[0], upper[1], upper[2]); - renderer->SetBackground(lower[0], lower[1], lower[2]); - m_GradientBackgroundFlag = true; -} + // add the displayed planes of the multiwidget to a node to which the subtree + // @a planesSubTree points ... -void QmitkStdMultiWidget::SetGradientBackgroundColors(const mitk::Color &upper, const mitk::Color &lower) -{ - for (unsigned int i = 0; i < 4; ++i) - { - vtkRenderer *renderer = GetRenderWindow(i)->GetRenderer()->GetVtkRenderer(); - renderer->SetBackground2(upper[0], upper[1], upper[2]); - renderer->SetBackground(lower[0], lower[1], lower[2]); - } - m_GradientBackgroundFlag = true; -} + mitk::PlaneGeometryDataMapper2D::Pointer mapper; -void QmitkStdMultiWidget::SetDepartmentLogo(const char *path) -{ - QImage* qimage = new QImage(path); - vtkSmartPointer qImageToVtk; - qImageToVtk = vtkSmartPointer::New(); + // ... of widget 1 + mitk::BaseRenderer* renderer1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow()); + m_PlaneNode1 = renderer1->GetCurrentWorldPlaneGeometryNode(); + m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); + m_PlaneNode1->SetProperty("name", mitk::StringProperty::New(std::string(renderer1->GetName()) + ".plane")); + m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); + m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); + mapper = mitk::PlaneGeometryDataMapper2D::New(); + m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); - qImageToVtk->SetQImage(qimage); - qImageToVtk->Update(); + // ... of widget 2 + mitk::BaseRenderer* renderer2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow()); + m_PlaneNode2 = renderer2->GetCurrentWorldPlaneGeometryNode(); + m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); + m_PlaneNode2->SetProperty("name", mitk::StringProperty::New(std::string(renderer2->GetName()) + ".plane")); + m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); + m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); + mapper = mitk::PlaneGeometryDataMapper2D::New(); + m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); - m_LogoRendering->SetLogoImage(qImageToVtk->GetOutput()); - mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow()); - m_LogoRendering->Update(renderer); - RequestUpdate(); -} + // ... of widget 3 + mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow()); + m_PlaneNode3 = renderer3->GetCurrentWorldPlaneGeometryNode(); + m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); + m_PlaneNode3->SetProperty("name", mitk::StringProperty::New(std::string(renderer3->GetName()) + ".plane")); + m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); + m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); + mapper = mitk::PlaneGeometryDataMapper2D::New(); + m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); -void QmitkStdMultiWidget::SetWidgetPlaneModeToSlicing(bool activate) -{ - if (activate) - { - this->SetWidgetPlaneMode(PLANE_MODE_SLICING); - } + m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); + m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New("Widgets")); + m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); } -void QmitkStdMultiWidget::SetWidgetPlaneModeToRotation(bool activate) +void QmitkStdMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) { - if (activate) - { - this->SetWidgetPlaneMode(PLANE_MODE_ROTATION); - } -} + mitk::Point2D pointOnDisplay; + renderer->WorldToDisplay(p, pointOnDisplay); -void QmitkStdMultiWidget::SetWidgetPlaneModeToSwivel(bool activate) -{ - if (activate) + if (pointOnDisplay[0] < renderer->GetVtkRenderer()->GetOrigin()[0] || + pointOnDisplay[1] < renderer->GetVtkRenderer()->GetOrigin()[1] || + pointOnDisplay[0] > renderer->GetVtkRenderer()->GetOrigin()[0] + renderer->GetViewportSize()[0] || + pointOnDisplay[1] > renderer->GetVtkRenderer()->GetOrigin()[1] + renderer->GetViewportSize()[1]) { - this->SetWidgetPlaneMode(PLANE_MODE_SWIVEL); + mitk::Point2D pointOnPlane; + renderer->GetCurrentWorldPlaneGeometry()->Map(p, pointOnPlane); + renderer->GetCameraController()->MoveCameraToPoint(pointOnPlane); } } -void QmitkStdMultiWidget::OnLayoutDesignChanged(int layoutDesignIndex) +void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer) { - switch (layoutDesignIndex) + auto dataStorage = GetDataStorage(); + if (nullptr != dataStorage) { - case LAYOUT_DEFAULT: - { - this->changeLayoutToDefault(); - break; - } - case LAYOUT_2D_IMAGES_UP: - { - this->changeLayoutTo2DImagesUp(); - break; - } - case LAYOUT_2D_IMAGES_LEFT: - { - this->changeLayoutTo2DImagesLeft(); - break; - } - case LAYOUT_BIG_3D: - { - this->changeLayoutToBig3D(); - break; - } - case LAYOUT_WIDGET1: + mitk::DataNode* dataNode = dataStorage->GetNamedNode(widgetName); + if (dataNode != nullptr) { - this->changeLayoutToWidget1(); - break; + dataNode->SetVisibility(visible, renderer); } - case LAYOUT_WIDGET2: - { - this->changeLayoutToWidget2(); - break; - } - case LAYOUT_WIDGET3: - { - this->changeLayoutToWidget3(); - break; - } - case LAYOUT_2X_2D_AND_3D_WIDGET: - { - this->changeLayoutTo2x2Dand3DWidget(); - break; - } - case LAYOUT_ROW_WIDGET_3_AND_4: - { - this->changeLayoutToRowWidget3And4(); - break; - } - case LAYOUT_COLUMN_WIDGET_3_AND_4: - { - this->changeLayoutToColumnWidget3And4(); - break; - } - case LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4: - { - this->changeLayoutToRowWidgetSmall3andBig4(); - break; - } - case LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4: - { - this->changeLayoutToSmallUpperWidget2Big3and4(); - break; - } - case LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET: - { - this->changeLayoutToLeft2Dand3DRight2D(); - break; - } - }; -} - -void QmitkStdMultiWidget::UpdateAllWidgets() -{ - mitkWidget1->resize(mitkWidget1Container->frameSize().width() - 1, mitkWidget1Container->frameSize().height()); - mitkWidget1->resize(mitkWidget1Container->frameSize().width(), mitkWidget1Container->frameSize().height()); - - mitkWidget2->resize(mitkWidget2Container->frameSize().width() - 1, mitkWidget2Container->frameSize().height()); - mitkWidget2->resize(mitkWidget2Container->frameSize().width(), mitkWidget2Container->frameSize().height()); - - mitkWidget3->resize(mitkWidget3Container->frameSize().width() - 1, mitkWidget3Container->frameSize().height()); - mitkWidget3->resize(mitkWidget3Container->frameSize().width(), mitkWidget3Container->frameSize().height()); - - mitkWidget4->resize(mitkWidget4Container->frameSize().width() - 1, mitkWidget4Container->frameSize().height()); - mitkWidget4->resize(mitkWidget4Container->frameSize().width(), mitkWidget4Container->frameSize().height()); -} - -void QmitkStdMultiWidget::HideAllWidgetToolbars() -{ - mitkWidget1->HideRenderWindowMenu(); - mitkWidget2->HideRenderWindowMenu(); - mitkWidget3->HideRenderWindowMenu(); - mitkWidget4->HideRenderWindowMenu(); -} - -void QmitkStdMultiWidget::ActivateMenuWidget(bool state) -{ - mitkWidget1->ActivateMenuWidget(state, this); - mitkWidget2->ActivateMenuWidget(state, this); - mitkWidget3->ActivateMenuWidget(state, this); - mitkWidget4->ActivateMenuWidget(state, this); -} - -bool QmitkStdMultiWidget::IsMenuWidgetEnabled() const -{ - return mitkWidget1->GetActivateMenuWidgetFlag(); + } } -void QmitkStdMultiWidget::SetDecorationColor(unsigned int widgetNumber, mitk::Color color) +void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { - switch (widgetNumber) + if (m_PlaneNode1.IsNotNull()) { - case 0: - if (m_PlaneNode1.IsNotNull()) - { - m_PlaneNode1->SetColor(color); - } - break; - case 1: - if (m_PlaneNode2.IsNotNull()) - { - m_PlaneNode2->SetColor(color); - } - break; - case 2: - if (m_PlaneNode3.IsNotNull()) - { - m_PlaneNode3->SetColor(color); - } - break; - case 3: - m_DecorationColorWidget4 = color; - break; - default: - MITK_ERROR << "Decoration color for unknown widget!"; - break; + m_PlaneNode1->SetVisibility(visible, renderer); } -} - -void QmitkStdMultiWidget::ResetCrosshair() -{ - if (m_DataStorage.IsNotNull()) + if (m_PlaneNode2.IsNotNull()) { - m_RenderingManager->InitializeViewsByBoundingObjects(m_DataStorage); - // m_RenderingManager->InitializeViews( m_DataStorage->ComputeVisibleBoundingGeometry3D() ); - // reset interactor to normal slicing - this->SetWidgetPlaneMode(PLANE_MODE_SLICING); + m_PlaneNode2->SetVisibility(visible, renderer); } -} - -void QmitkStdMultiWidget::EnableColoredRectangles() -{ - m_RectangleProps[0]->SetVisibility(1); - m_RectangleProps[1]->SetVisibility(1); - m_RectangleProps[2]->SetVisibility(1); - m_RectangleProps[3]->SetVisibility(1); -} - -void QmitkStdMultiWidget::DisableColoredRectangles() -{ - m_RectangleProps[0]->SetVisibility(0); - m_RectangleProps[1]->SetVisibility(0); - m_RectangleProps[2]->SetVisibility(0); - m_RectangleProps[3]->SetVisibility(0); -} - -bool QmitkStdMultiWidget::IsColoredRectanglesEnabled() const -{ - return m_RectangleProps[0]->GetVisibility() > 0; -} - -mitk::MouseModeSwitcher *QmitkStdMultiWidget::GetMouseModeSwitcher() -{ - return m_MouseModeSwitcher; -} - -mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() -{ - return this->m_PlaneNode1; -} - -mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() -{ - return this->m_PlaneNode2; -} - -mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() -{ - return this->m_PlaneNode3; -} - -mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(int id) -{ - switch (id) + if (m_PlaneNode3.IsNotNull()) { - case 1: - return this->m_PlaneNode1; - break; - case 2: - return this->m_PlaneNode2; - break; - case 3: - return this->m_PlaneNode3; - break; - default: - return nullptr; + m_PlaneNode3->SetVisibility(visible, renderer); } + GetRenderingManager()->RequestUpdateAll(); +} + +////////////////////////////////////////////////////////////////////////// +// PRIVATE +////////////////////////////////////////////////////////////////////////// +void QmitkStdMultiWidget::SetLayoutImpl() +{ + CreateRenderWindowWidgets(); + GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); + + // Initialize views as axial, sagittal, coronal to all data objects in DataStorage + auto geo = GetDataStorage()->ComputeBoundingGeometry3D(GetDataStorage()->GetAll()); + GetRenderingManager()->InitializeViews(geo); +} + +void QmitkStdMultiWidget::CreateRenderWindowWidgets() +{ + // create axial render window (widget) + QString renderWindowWidgetName = GetNameFromIndex(0, 0); + RenderWindowWidgetPointer renderWindowWidget1 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + auto renderWindow1 = renderWindowWidget1->GetRenderWindow(); + renderWindow1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + renderWindowWidget1->SetDecorationColor(GetDecorationColor(0)); + renderWindowWidget1->SetCornerAnnotationText("Axial"); + renderWindowWidget1->GetRenderWindow()->SetLayoutIndex(ViewDirection::AXIAL); + AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget1); + + // create sagittal render window (widget) + renderWindowWidgetName = GetNameFromIndex(0, 1); + RenderWindowWidgetPointer renderWindowWidget2 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + auto renderWindow2 = renderWindowWidget2->GetRenderWindow(); + renderWindow2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + renderWindowWidget2->SetDecorationColor(GetDecorationColor(1)); + renderWindowWidget2->setStyleSheet("border: 0px"); + renderWindowWidget2->SetCornerAnnotationText("Sagittal"); + renderWindowWidget2->GetRenderWindow()->SetLayoutIndex(ViewDirection::SAGITTAL); + AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget2); + + // create coronal render window (widget) + renderWindowWidgetName = GetNameFromIndex(1, 0); + RenderWindowWidgetPointer renderWindowWidget3 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + auto renderWindow3 = renderWindowWidget3->GetRenderWindow(); + renderWindow3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); + renderWindowWidget3->SetDecorationColor(GetDecorationColor(2)); + renderWindowWidget3->SetCornerAnnotationText("Coronal"); + renderWindowWidget3->GetRenderWindow()->SetLayoutIndex(ViewDirection::CORONAL); + AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget3); + + // create 3D render window (widget) + renderWindowWidgetName = GetNameFromIndex(1, 1); + RenderWindowWidgetPointer renderWindowWidget4 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + auto renderWindow4 = renderWindowWidget4->GetRenderWindow(); + renderWindow4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); + renderWindowWidget4->SetDecorationColor(GetDecorationColor(3)); + renderWindowWidget4->SetCornerAnnotationText("3D"); + renderWindowWidget4->GetRenderWindow()->SetLayoutIndex(ViewDirection::THREE_D); + mitk::BaseRenderer::GetInstance(renderWindowWidget4->GetRenderWindow()->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); + AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget4); + + SetActiveRenderWindowWidget(renderWindowWidget1); + + // connect to the "time navigation controller": send time via sliceNavigationControllers + m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow1->GetSliceNavigationController(), false); + m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow2->GetSliceNavigationController(), false); + m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow3->GetSliceNavigationController(), false); + m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow4->GetSliceNavigationController(), false); + renderWindow1->GetSliceNavigationController()->ConnectGeometrySendEvent( + mitk::BaseRenderer::GetInstance(renderWindow4->GetRenderWindow())); + + // reverse connection between sliceNavigationControllers and timeNavigationController + renderWindow1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); + renderWindow2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); + renderWindow3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); + //renderWindow4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); + + auto layoutManager = GetMultiWidgetLayoutManager(); + connect(renderWindowWidget1.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); + connect(renderWindow1, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); + connect(renderWindow1, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); + connect(renderWindow1, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); + connect(renderWindow1, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); + + connect(renderWindowWidget2.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); + connect(renderWindow2, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); + connect(renderWindow2, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); + connect(renderWindow2, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); + connect(renderWindow2, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); + + connect(renderWindowWidget3.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); + connect(renderWindow3, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); + connect(renderWindow3, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); + connect(renderWindow3, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); + connect(renderWindow3, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); + + connect(renderWindowWidget4.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); + connect(renderWindow4, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); + connect(renderWindow4, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); + connect(renderWindow4, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); + connect(renderWindow4, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); } diff --git a/Modules/QtWidgetsExt/src/QmitkPointListView.cpp b/Modules/QtWidgetsExt/src/QmitkPointListView.cpp index 0480ab1361..973005a7b1 100644 --- a/Modules/QtWidgetsExt/src/QmitkPointListView.cpp +++ b/Modules/QtWidgetsExt/src/QmitkPointListView.cpp @@ -1,334 +1,338 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPointListView.h" #include "QmitkEditPointDialog.h" #include "QmitkPointListModel.h" +#include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "mitkRenderingManager.h" #include #include #include #include #include QmitkPointListView::QmitkPointListView(QWidget *parent) : QListView(parent), m_PointListModel(new QmitkPointListModel()), m_SelfCall(false), m_showFading(false), m_MultiWidget(nullptr) { QListView::setAlternatingRowColors(true); QListView::setSelectionBehavior(QAbstractItemView::SelectItems); QListView::setSelectionMode(QAbstractItemView::SingleSelection); QListView::setModel(m_PointListModel); QString tooltip = QString("Use the F2/F3 keys to move a point up/down, the Del key to remove a point\nand the mouse " "wheel to change the timestep.\n\nTimeStep:\t%1") .arg(0); QListView::setToolTip(tooltip); this->setContextMenuPolicy(Qt::CustomContextMenu); this->setMinimumHeight(40); this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); connect(m_PointListModel, SIGNAL(SignalUpdateSelection()), this, SLOT(OnPointSetSelectionChanged())); connect(this, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(OnPointDoubleClicked(const QModelIndex &))); connect(QListView::selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT(OnListViewSelectionChanged(const QItemSelection &, const QItemSelection &))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ctxMenu(const QPoint &))); } QmitkPointListView::~QmitkPointListView() { delete m_PointListModel; } void QmitkPointListView::SetPointSetNode(mitk::DataNode *pointSetNode) { m_PointListModel->SetPointSetNode(pointSetNode); } const mitk::PointSet *QmitkPointListView::GetPointSet() const { return m_PointListModel->GetPointSet(); } void QmitkPointListView::SetMultiWidget(QmitkStdMultiWidget *multiWidget) { m_MultiWidget = multiWidget; - this->AddSliceNavigationController(multiWidget->mitkWidget1->GetSliceNavigationController()); - this->AddSliceNavigationController(multiWidget->mitkWidget2->GetSliceNavigationController()); - this->AddSliceNavigationController(multiWidget->mitkWidget3->GetSliceNavigationController()); + if (nullptr != m_MultiWidget) + { + AddSliceNavigationController(m_MultiWidget->GetRenderWindow1()->GetSliceNavigationController()); + AddSliceNavigationController(m_MultiWidget->GetRenderWindow2()->GetSliceNavigationController()); + AddSliceNavigationController(m_MultiWidget->GetRenderWindow3()->GetSliceNavigationController()); + } } QmitkStdMultiWidget *QmitkPointListView::GetMultiWidget() const { return m_MultiWidget; } void QmitkPointListView::OnPointDoubleClicked(const QModelIndex &index) { mitk::PointSet::PointType p; mitk::PointSet::PointIdentifier id; m_PointListModel->GetPointForModelIndex(index, p, id); QmitkEditPointDialog _EditPointDialog(this); _EditPointDialog.SetPoint(m_PointListModel->GetPointSet(), id, m_PointListModel->GetTimeStep()); _EditPointDialog.exec(); } void QmitkPointListView::OnPointSetSelectionChanged() { const mitk::PointSet *pointSet = m_PointListModel->GetPointSet(); if (pointSet == nullptr) return; // update this view's selection status as a result to changes in the point set data structure m_SelfCall = true; int timeStep = m_PointListModel->GetTimeStep(); if (pointSet->GetNumberOfSelected(timeStep) > 1) { MITK_ERROR << "Point set has multiple selected points. This view is not designed for more than one selected point."; } int selectedIndex = pointSet->SearchSelectedPoint(timeStep); if (selectedIndex == -1) // no selected point is found { m_SelfCall = false; return; } QModelIndex index; bool modelIndexOkay = m_PointListModel->GetModelIndexForPointID(selectedIndex, index); if (modelIndexOkay == true) QListView::selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); emit SignalPointSelectionChanged(); m_SelfCall = false; } void QmitkPointListView::OnListViewSelectionChanged(const QItemSelection &selected, const QItemSelection & /*deselected*/) { if (m_SelfCall) return; mitk::PointSet *pointSet = const_cast(m_PointListModel->GetPointSet()); if (pointSet == nullptr) return; // (take care that this widget doesn't react to self-induced changes by setting m_SelfCall) m_SelfCall = true; // update selection of all points in pointset: select the one(s) that are selected in the view, deselect all others QModelIndexList selectedIndexes = selected.indexes(); // only call setSelectInfo on a point set with 'selected = true' if you deselcted the other entries int indexToSelect = -1; for (mitk::PointSet::PointsContainer::Iterator it = pointSet->GetPointSet(m_PointListModel->GetTimeStep())->GetPoints()->Begin(); it != pointSet->GetPointSet(m_PointListModel->GetTimeStep())->GetPoints()->End(); ++it) { QModelIndex index; if (m_PointListModel->GetModelIndexForPointID(it->Index(), index)) { if (selectedIndexes.indexOf(index) != -1) // index is found in the selected indices list { indexToSelect = it->Index(); } else { pointSet->SetSelectInfo(it->Index(), false, m_PointListModel->GetTimeStep()); } } } // force selection of only one index after deselecting the others if (indexToSelect > -1) { pointSet->SetSelectInfo(indexToSelect, true, m_PointListModel->GetTimeStep()); mitk::Point3D p = pointSet->GetPoint(indexToSelect, m_PointListModel->GetTimeStep()); for (auto snc : m_Sncs) snc->SelectSliceByPoint(p); } m_SelfCall = false; emit SignalPointSelectionChanged(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPointListView::keyPressEvent(QKeyEvent *e) { if (m_PointListModel == nullptr) return; int key = e->key(); switch (key) { case Qt::Key_F2: m_PointListModel->MoveSelectedPointUp(); break; case Qt::Key_F3: m_PointListModel->MoveSelectedPointDown(); break; case Qt::Key_Delete: m_PointListModel->RemoveSelectedPoint(); break; default: break; } } void QmitkPointListView::wheelEvent(QWheelEvent *event) { if (!m_PointListModel || !m_PointListModel->GetPointSet() || (int)(m_PointListModel->GetPointSet()->GetTimeSteps()) == 1) return; int whe = event->delta(); mitk::PointSet::Pointer ps = dynamic_cast(m_PointListModel->GetPointSet()); unsigned int numberOfTS = ps->GetTimeSteps(); if (numberOfTS == 1) return; int currentTS = this->m_PointListModel->GetTimeStep(); if (whe > 0) { if ((currentTS + 1 >= (int)numberOfTS)) return; this->m_PointListModel->SetTimeStep(++currentTS); } else { if ((currentTS <= 0)) return; this->m_PointListModel->SetTimeStep(--currentTS); } QString tooltip = QString("Use the F2/F3 keys to move a point up/down, the Del key to remove a point\nand the mouse " "wheel to change the timestep.\n\nTimeStep:\t%1") .arg(currentTS); this->setToolTip(tooltip); emit SignalTimeStepChanged(currentTS); } void QmitkPointListView::ctxMenu(const QPoint &pos) { QMenu *menu = new QMenu; // add Fading check QAction *showFading = new QAction(this); showFading->setCheckable(false); // TODO: reset when fading is working showFading->setEnabled(false); // TODO: reset when fading is working showFading->setText("Fade TimeStep"); connect(showFading, SIGNAL(triggered(bool)), this, SLOT(SetFading(bool))); menu->addAction(showFading); // add Clear action QAction *clearList = new QAction(this); clearList->setText("Clear List"); connect(clearList, SIGNAL(triggered()), this, SLOT(ClearPointList())); menu->addAction(clearList); // add Clear TimeStep action QAction *clearTS = new QAction(this); clearTS->setText("Clear current time step"); connect(clearTS, SIGNAL(triggered()), this, SLOT(ClearPointListTS())); menu->addAction(clearTS); menu->exec(this->mapToGlobal(pos)); } void QmitkPointListView::SetFading(bool onOff) { m_showFading = onOff; } void QmitkPointListView::ClearPointList() { if (!m_PointListModel->GetPointSet()) return; mitk::PointSet::Pointer curPS = m_PointListModel->GetPointSet(); if (curPS->GetSize() == 0) return; switch (QMessageBox::question(this, tr("Clear Points"), tr("Remove all points from the displayed list?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) { case QMessageBox::Yes: { mitk::PointSet::PointsIterator it; mitk::PointSet::PointsContainer *curPsPoints; while (!curPS->IsEmptyTimeStep(0)) { curPsPoints = curPS->GetPointSet()->GetPoints(); it = curPsPoints->Begin(); curPS->SetSelectInfo(it->Index(), true); m_PointListModel->RemoveSelectedPoint(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case QMessageBox::No: default: break; } } void QmitkPointListView::ClearPointListTS() { } void QmitkPointListView::AddSliceNavigationController(mitk::SliceNavigationController *snc) { if (snc == nullptr) return; m_Sncs.insert(snc); } void QmitkPointListView::RemoveSliceNavigationController(mitk::SliceNavigationController *snc) { if (snc == nullptr) return; m_Sncs.erase(snc); } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp index 87214ffa53..2489423f70 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp @@ -1,605 +1,605 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageTreeModel.h" // mitk core #include // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include "QmitkMimeTypes.h" #include "QmitkNodeDescriptorManager.h" QmitkRenderWindowDataStorageTreeModel::QmitkRenderWindowDataStorageTreeModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) , m_Root(nullptr) { m_RenderWindowLayerController = std::make_unique(); ResetTree(); } void QmitkRenderWindowDataStorageTreeModel::DataStorageChanged() { m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock()); ResetTree(); UpdateModelData(); } void QmitkRenderWindowDataStorageTreeModel::NodePredicateChanged() { ResetTree(); UpdateModelData(); } void QmitkRenderWindowDataStorageTreeModel::NodeAdded(const mitk::DataNode* node) { for (const auto renderer : m_ControlledRenderer) { // add the node to each render window mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(const_cast(node), renderer); } if (!m_BaseRenderer.IsExpired()) { auto baseRenderer = m_BaseRenderer.Lock(); AddNodeInternal(node, baseRenderer); } } void QmitkRenderWindowDataStorageTreeModel::NodeChanged(const mitk::DataNode* node) { auto item = m_Root->Find(node); if (nullptr != item) { auto parentItem = item->GetParent(); // as the root node should not be removed one should always have a parent item if (nullptr == parentItem) { return; } auto index = createIndex(item->GetIndex(), 0, item); emit dataChanged(index, index); } } void QmitkRenderWindowDataStorageTreeModel::NodeRemoved(const mitk::DataNode* node) { RemoveNodeInternal(node); } QModelIndex QmitkRenderWindowDataStorageTreeModel::index(int row, int column, const QModelIndex& parent) const { auto item = GetItemByIndex(parent); if (nullptr != item) { item = item->GetChild(row); } if (nullptr == item) { return QModelIndex(); } return createIndex(row, column, item); } QModelIndex QmitkRenderWindowDataStorageTreeModel::parent(const QModelIndex& parent) const { auto item = GetItemByIndex(parent); if (nullptr != item) { item = item->GetParent(); } if(nullptr == item) { return QModelIndex(); } if (item == m_Root) { return QModelIndex(); } return createIndex(item->GetIndex(), 0, item); } int QmitkRenderWindowDataStorageTreeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { auto item = GetItemByIndex(parent); if (nullptr == item) { return 0; } return item->GetChildCount(); } int QmitkRenderWindowDataStorageTreeModel::columnCount(const QModelIndex&/* parent = QModelIndex()*/) const { if (0 == m_Root->GetChildCount()) { // no items stored, no need to display columns return 0; } return 1; } QVariant QmitkRenderWindowDataStorageTreeModel::data(const QModelIndex& index, int role) const { if (m_BaseRenderer.IsExpired()) { return QVariant(); } auto baseRenderer = m_BaseRenderer.Lock(); if (!index.isValid() || this != index.model()) { return QVariant(); } auto item = GetItemByIndex(index); if (nullptr == item) { return QVariant(); } auto dataNode = item->GetDataNode(); if (nullptr == dataNode) { return QVariant(); } if (Qt::CheckStateRole == role) { bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); if (visibility) { return Qt::Checked; } else { return Qt::Unchecked; } } else if (Qt::DisplayRole == role) { return QVariant(QString::fromStdString(dataNode->GetName())); } else if (Qt::ToolTipRole == role) { return QVariant("Name of the data node."); } else if (Qt::DecorationRole == role) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role) { // user role always returns a reference to the data node, // which can be used to modify the data node in the data storage return QVariant::fromValue(dataNode); } else if (QmitkDataNodeRole == role) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } return QVariant(); } bool QmitkRenderWindowDataStorageTreeModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) { if (m_BaseRenderer.IsExpired()) { return false; } auto baseRenderer = m_BaseRenderer.Lock(); if (!index.isValid() || this != index.model()) { return false; } auto item = GetItemByIndex(index); if (nullptr == item) { return false; } auto dataNode = item->GetDataNode(); if (nullptr == dataNode) { return false; } if (Qt::EditRole == role && !value.toString().isEmpty()) { dataNode->SetName(value.toString().toStdString().c_str()); emit dataChanged(index, index); return true; } if (Qt::CheckStateRole == role) { Qt::CheckState newCheckState = static_cast(value.toInt()); bool isVisible = newCheckState; dataNode->SetVisibility(isVisible, baseRenderer); emit dataChanged(index, index); mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); return true; } return false; } Qt::ItemFlags QmitkRenderWindowDataStorageTreeModel::flags(const QModelIndex& index) const { if (this != index.model()) { return Qt::NoItemFlags; } if (!index.isValid()) { return Qt::ItemIsDropEnabled; } auto item = GetItemByIndex(index); if (nullptr == item) { return Qt::NoItemFlags; } const auto dataNode = item->GetDataNode(); if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::NoItemFlags; } Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList QmitkRenderWindowDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << QmitkMimeTypes::DataNodePtrs; return types; } QMimeData* QmitkRenderWindowDataStorageTreeModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const auto& index : indexes) { if (index.isValid()) { auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); stream << reinterpret_cast(dataNode); } } mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); return mimeData; } bool QmitkRenderWindowDataStorageTreeModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent) { if (m_BaseRenderer.IsExpired()) { return false; } auto baseRenderer = m_BaseRenderer.Lock(); if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { return false; } if (!parent.isValid()) { return false; } int layer = -1; auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); if (nullptr != dataNode) { dataNode->GetIntProperty("layer", layer, baseRenderer); } auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); for (const auto& dataNode : dataNodeList) { m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); } ResetTree(); UpdateModelData(); AdjustLayerProperty(); return true; } void QmitkRenderWindowDataStorageTreeModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_ControlledRenderer = controlledRenderer; ResetTree(); if (m_DataStorage.IsExpired()) { return; } auto dataStorage = m_DataStorage.Lock(); for (const auto& renderer : controlledRenderer) { if (nullptr == renderer) { continue; } auto allDataNodes = dataStorage->GetAll(); for (const auto& dataNode : *allDataNodes) { // add the node to each render window mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer); } } } void QmitkRenderWindowDataStorageTreeModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) { if (m_BaseRenderer == baseRenderer) { return; } // base renderer changed // reset tree to build a new renderer-specific item hierarchy m_BaseRenderer = baseRenderer; ResetTree(); UpdateModelData(); } mitk::BaseRenderer* QmitkRenderWindowDataStorageTreeModel::GetCurrentRenderer() const { if (m_BaseRenderer.IsExpired()) { return nullptr; } return m_BaseRenderer.Lock().GetPointer(); } void QmitkRenderWindowDataStorageTreeModel::ResetTree() { beginResetModel(); if (nullptr != m_Root) { m_Root->Delete(); } - endResetModel(); mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Storage"); m_Root = new QmitkDataStorageTreeModelInternalItem(rootDataNode); + endResetModel(); } void QmitkRenderWindowDataStorageTreeModel::UpdateModelData() { if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); if (!m_BaseRenderer.IsExpired()) { auto baseRenderer = m_BaseRenderer.Lock(); mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(baseRenderer); auto filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate); for (const auto& dataNode : *filteredDataNodes) { AddNodeInternal(dataNode, baseRenderer); } } } } void QmitkRenderWindowDataStorageTreeModel::AdjustLayerProperty() { if (m_BaseRenderer.IsExpired()) { return; } auto baseRenderer = m_BaseRenderer.Lock(); std::vector treeAsVector; TreeToVector(m_Root, treeAsVector); int i = treeAsVector.size() - 1; for (auto it = treeAsVector.begin(); it != treeAsVector.end(); ++it) { auto dataNode = (*it)->GetDataNode(); dataNode->SetIntProperty("layer", i, baseRenderer); --i; } } void QmitkRenderWindowDataStorageTreeModel::TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const { QmitkDataStorageTreeModelInternalItem* item; for (int i = 0; i < parent->GetChildCount(); ++i) { item = parent->GetChild(i); TreeToVector(item, treeAsVector); treeAsVector.push_back(item); } } void QmitkRenderWindowDataStorageTreeModel::AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer) { if (nullptr == dataNode || m_DataStorage.IsExpired() || nullptr != m_Root->Find(dataNode)) { return; } // find out if we have a root node auto parentItem = m_Root; QModelIndex index; auto parentDataNode = GetParentNode(dataNode); if (nullptr != parentDataNode) // no top level data node { parentItem = m_Root->Find(parentDataNode); if (nullptr == parentItem) { // parent node not contained in the tree; add it NodeAdded(parentDataNode); parentItem = m_Root->Find(parentDataNode); if (nullptr == parentItem) { // could not find and add the parent tree; abort return; } } // get the index of this parent with the help of the grand parent index = createIndex(parentItem->GetIndex(), 0, parentItem); } int firstRowWithASiblingBelow = 0; int nodeLayer = -1; dataNode->GetIntProperty("layer", nodeLayer, renderer); for (const auto& siblingItem : parentItem->GetChildren()) { int siblingLayer = -1; auto siblingNode = siblingItem->GetDataNode(); if (nullptr != siblingNode) { siblingNode->GetIntProperty("layer", siblingLayer, renderer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); auto newNode = new QmitkDataStorageTreeModelInternalItem(const_cast(dataNode)); parentItem->InsertChild(newNode, firstRowWithASiblingBelow); endInsertRows(); } void QmitkRenderWindowDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode* dataNode) { if (nullptr == dataNode || nullptr == m_Root) { return; } auto item = m_Root->Find(dataNode); if (nullptr == item) { return; } auto parentItem = item->GetParent(); auto parentIndex = GetIndexByItem(parentItem); auto children = item->GetChildren(); beginRemoveRows(parentIndex, item->GetIndex(), item->GetIndex()); parentItem->RemoveChild(item); delete item; endRemoveRows(); if (!children.empty()) { // rebuild tree because children could not be at the top level ResetTree(); UpdateModelData(); } } mitk::DataNode* QmitkRenderWindowDataStorageTreeModel::GetParentNode(const mitk::DataNode* node) const { mitk::DataNode* dataNode = nullptr; if (m_DataStorage.IsExpired()) { return dataNode; } auto sources = m_DataStorage.Lock()->GetSources(node); if (sources->empty()) { return dataNode; } return sources->front(); } QmitkDataStorageTreeModelInternalItem* QmitkRenderWindowDataStorageTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { return static_cast(index.internalPointer()); } return m_Root; } QModelIndex QmitkRenderWindowDataStorageTreeModel::GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const { if (item == m_Root) { return QModelIndex(); } return createIndex(item->GetIndex(), 0, item); } diff --git a/Modules/Segmentation/Interactions/mitkTool.cpp b/Modules/Segmentation/Interactions/mitkTool.cpp index 5e01e872b1..27bd37ed14 100644 --- a/Modules/Segmentation/Interactions/mitkTool.cpp +++ b/Modules/Segmentation/Interactions/mitkTool.cpp @@ -1,323 +1,334 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTool.h" #include #include "mitkDisplayInteractor.h" +#include "mitkDisplayActionEventBroadcast.h" #include "mitkImageReadAccessor.h" #include "mitkImageWriteAccessor.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" #include // us #include #include // itk #include mitk::Tool::Tool(const char *type, const us::Module *interactorModule) : m_EventConfig("DisplayConfigMITK.xml"), m_ToolManager(nullptr), m_PredicateImages(NodePredicateDataType::New("Image")), // for reference images m_PredicateDim3(NodePredicateDimension::New(3, 1)), m_PredicateDim4(NodePredicateDimension::New(4, 1)), m_PredicateDimension(mitk::NodePredicateOr::New(m_PredicateDim3, m_PredicateDim4)), m_PredicateImage3D(NodePredicateAnd::New(m_PredicateImages, m_PredicateDimension)), m_PredicateBinary(NodePredicateProperty::New("binary", BoolProperty::New(true))), m_PredicateNotBinary(NodePredicateNot::New(m_PredicateBinary)), m_PredicateSegmentation(NodePredicateProperty::New("segmentation", BoolProperty::New(true))), m_PredicateNotSegmentation(NodePredicateNot::New(m_PredicateSegmentation)), m_PredicateHelper(NodePredicateProperty::New("helper object", BoolProperty::New(true))), m_PredicateNotHelper(NodePredicateNot::New(m_PredicateHelper)), m_PredicateImageColorful(NodePredicateAnd::New(m_PredicateNotBinary, m_PredicateNotSegmentation)), m_PredicateImageColorfulNotHelper(NodePredicateAnd::New(m_PredicateImageColorful, m_PredicateNotHelper)), m_PredicateReference(NodePredicateAnd::New(m_PredicateImage3D, m_PredicateImageColorfulNotHelper)), m_IsSegmentationPredicate( NodePredicateAnd::New(NodePredicateOr::New(m_PredicateBinary, m_PredicateSegmentation), m_PredicateNotHelper)), m_InteractorType(type), m_DisplayInteractorConfigs(), m_InteractorModule(interactorModule) { } mitk::Tool::~Tool() { } bool mitk::Tool::CanHandle(BaseData *) const { return true; } void mitk::Tool::InitializeStateMachine() { if (m_InteractorType.empty()) return; try { auto isThisModule = nullptr == m_InteractorModule; auto module = isThisModule ? us::GetModuleContext()->GetModule() : m_InteractorModule; LoadStateMachine(m_InteractorType + ".xml", module); SetEventConfig(isThisModule ? "SegmentationToolsConfig.xml" : m_InteractorType + "Config.xml", module); } catch (const std::exception &e) { MITK_ERROR << "Could not load statemachine pattern " << m_InteractorType << ".xml with exception: " << e.what(); } } void mitk::Tool::Notify(InteractionEvent *interactionEvent, bool isHandled) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if (!isHandled) { this->HandleEvent(interactionEvent, nullptr); } } void mitk::Tool::ConnectActionsAndFunctions() { } bool mitk::Tool::FilterEvents(InteractionEvent *, DataNode *) { return true; } const char *mitk::Tool::GetGroup() const { return "default"; } void mitk::Tool::SetToolManager(ToolManager *manager) { m_ToolManager = manager; } void mitk::Tool::Activated() { // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts // with tools // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction // will still be enabled m_DisplayInteractorConfigs.clear(); std::vector> listEventObserver = us::GetModuleContext()->GetServiceReferences(); - for (auto it = listEventObserver.begin(); - it != listEventObserver.end(); - ++it) + for (auto it = listEventObserver.begin(); it != listEventObserver.end(); ++it) { - auto *displayInteractor = - dynamic_cast(us::GetModuleContext()->GetService(*it)); + auto displayInteractor = dynamic_cast(us::GetModuleContext()->GetService(*it)); if (displayInteractor != nullptr) { // remember the original configuration m_DisplayInteractorConfigs.insert(std::make_pair(*it, displayInteractor->GetEventConfig())); // here the alternative configuration is loaded displayInteractor->SetEventConfig(m_EventConfig.c_str()); } + + auto displayActionEventBroadcast = dynamic_cast(us::GetModuleContext()->GetService(*it)); + if (displayActionEventBroadcast != nullptr) + { + // remember the original configuration + m_DisplayInteractorConfigs.insert(std::make_pair(*it, displayActionEventBroadcast->GetEventConfig())); + // here the alternative configuration is loaded + displayActionEventBroadcast->SetEventConfig(m_EventConfig.c_str()); + } } } void mitk::Tool::Deactivated() { // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools // in new interaction framework - for (auto it = m_DisplayInteractorConfigs.begin(); - it != m_DisplayInteractorConfigs.end(); - ++it) + for (auto it = m_DisplayInteractorConfigs.begin(); it != m_DisplayInteractorConfigs.end(); ++it) { if (it->first) { - DisplayInteractor *displayInteractor = - static_cast(us::GetModuleContext()->GetService(it->first)); + auto displayInteractor = static_cast(us::GetModuleContext()->GetService(it->first)); if (displayInteractor != nullptr) { // here the regular configuration is loaded again displayInteractor->SetEventConfig(it->second); } + + auto displayActionEventBroadcast = dynamic_cast(us::GetModuleContext()->GetService(it->first)); + if (displayActionEventBroadcast != nullptr) + { + // here the regular configuration is loaded again + displayActionEventBroadcast->SetEventConfig(it->second); + } } } m_DisplayInteractorConfigs.clear(); } itk::Object::Pointer mitk::Tool::GetGUI(const std::string &toolkitPrefix, const std::string &toolkitPostfix) { itk::Object::Pointer object; std::string classname = this->GetNameOfClass(); std::string guiClassname = toolkitPrefix + classname + toolkitPostfix; std::list allGUIs = itk::ObjectFactoryBase::CreateAllInstance(guiClassname.c_str()); for (auto iter = allGUIs.begin(); iter != allGUIs.end(); ++iter) { if (object.IsNull()) { object = dynamic_cast(iter->GetPointer()); } else { MITK_ERROR << "There is more than one GUI for " << classname << " (several factories claim ability to produce a " << guiClassname << " ) " << std::endl; return nullptr; // people should see and fix this error } } return object; } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetReferenceDataPreference() const { return m_PredicateReference.GetPointer(); } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetWorkingDataPreference() const { return m_IsSegmentationPredicate.GetPointer(); } mitk::DataNode::Pointer mitk::Tool::CreateEmptySegmentationNode(Image *original, const std::string &organName, const mitk::Color &color) { // we NEED a reference image for size etc. if (!original) return nullptr; // actually create a new empty segmentation PixelType pixelType(mitk::MakeScalarPixelType()); LabelSetImage::Pointer segmentation = LabelSetImage::New(); if (original->GetDimension() == 2) { const unsigned int dimensions[] = {original->GetDimension(0), original->GetDimension(1), 1}; segmentation->Initialize(pixelType, 3, dimensions); segmentation->AddLayer(); } else { segmentation->Initialize(original); } mitk::Label::Pointer label = mitk::Label::New(); label->SetName(organName); label->SetColor(color); label->SetValue(1); segmentation->GetActiveLabelSet()->AddLabel(label); segmentation->GetActiveLabelSet()->SetActiveLabel(1); unsigned int byteSize = sizeof(mitk::Label::PixelType); if (segmentation->GetDimension() < 4) { for (unsigned int dim = 0; dim < segmentation->GetDimension(); ++dim) { byteSize *= segmentation->GetDimension(dim); } mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(0)); memset(writeAccess.GetData(), 0, byteSize); } else { // if we have a time-resolved image we need to set memory to 0 for each time step for (unsigned int dim = 0; dim < 3; ++dim) { byteSize *= segmentation->GetDimension(dim); } for (unsigned int volumeNumber = 0; volumeNumber < segmentation->GetDimension(3); volumeNumber++) { mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(volumeNumber)); memset(writeAccess.GetData(), 0, byteSize); } } if (original->GetTimeGeometry()) { TimeGeometry::Pointer originalGeometry = original->GetTimeGeometry()->Clone(); segmentation->SetTimeGeometry(originalGeometry); } else { Tool::ErrorMessage("Original image does not have a 'Time sliced geometry'! Cannot create a segmentation."); return nullptr; } return CreateSegmentationNode(segmentation, organName, color); } mitk::DataNode::Pointer mitk::Tool::CreateSegmentationNode(Image *image, const std::string &organName, const mitk::Color &color) { if (!image) return nullptr; // decorate the datatreenode with some properties DataNode::Pointer segmentationNode = DataNode::New(); segmentationNode->SetData(image); // name segmentationNode->SetProperty("name", StringProperty::New(organName)); // visualization properties segmentationNode->SetProperty("binary", BoolProperty::New(true)); segmentationNode->SetProperty("color", ColorProperty::New(color)); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::MULTILABEL); mitk::LookupTableProperty::Pointer lutProp = mitk::LookupTableProperty::New(); lutProp->SetLookupTable(lut); segmentationNode->SetProperty("LookupTable", lutProp); segmentationNode->SetProperty("texture interpolation", BoolProperty::New(false)); segmentationNode->SetProperty("layer", IntProperty::New(10)); segmentationNode->SetProperty("levelwindow", LevelWindowProperty::New(LevelWindow(0.5, 1))); segmentationNode->SetProperty("opacity", FloatProperty::New(0.3)); segmentationNode->SetProperty("segmentation", BoolProperty::New(true)); segmentationNode->SetProperty("reslice interpolation", VtkResliceInterpolationProperty::New()); // otherwise -> segmentation appears in 2 // slices sometimes (only visual effect, not // different data) // For MITK-3M3 release, the volume of all segmentations should be shown segmentationNode->SetProperty("showVolume", BoolProperty::New(true)); return segmentationNode; } us::ModuleResource mitk::Tool::GetIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } us::ModuleResource mitk::Tool::GetCursorIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp index 20ef1b65eb..d8867ee81c 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp @@ -1,970 +1,952 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkAdaptiveRegionGrowingToolGUI.h" -#include "QmitkStdMultiWidget.h" - #include #include "mitkITKImageImport.h" #include "mitkImageAccessByItk.h" #include "mitkImageTimeSelector.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkTransferFunctionProperty.h" #include "mitkImageStatisticsHolder.h" #include "itkMaskImageFilter.h" #include "itkNumericTraits.h" #include #include #include #include #include "QmitkConfirmSegmentationDialog.h" #include "itkOrImageFilter.h" #include "mitkImageCast.h" #include "mitkImagePixelReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include "mitkImageCast.h" MITK_TOOL_GUI_MACRO(, QmitkAdaptiveRegionGrowingToolGUI, "") QmitkAdaptiveRegionGrowingToolGUI::QmitkAdaptiveRegionGrowingToolGUI(QWidget *parent) : QmitkToolGUI(), - m_MultiWidget(nullptr), m_DataStorage(nullptr), m_UseVolumeRendering(false), m_UpdateSuggestedThreshold(true), m_SuggestedThValue(0.0) { this->setParent(parent); m_Controls.setupUi(this); m_Controls.m_ThresholdSlider->setDecimals(1); m_Controls.m_ThresholdSlider->setSpinBoxAlignment(Qt::AlignVCenter); m_Controls.m_PreviewSlider->setEnabled(false); m_Controls.m_PreviewSlider->setSingleStep(0.5); // Not yet available // m_Controls.m_PreviewSlider->InvertedAppearance(true); //3D preview doesn't work: T24430. Postponed until reimplementation of segmentation m_Controls.m_cbVolumeRendering->setVisible(false); this->CreateConnections(); this->SetDataNodeNames("labeledRGSegmentation", "RGResult", "RGFeedbackSurface", "maskedSegmentation"); connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); } QmitkAdaptiveRegionGrowingToolGUI::~QmitkAdaptiveRegionGrowingToolGUI() { // Removing the observer of the PointSet node if (m_RegionGrow3DTool->GetPointSetNode().IsNotNull()) { m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetAddObserverTag); m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetMoveObserverTag); } this->RemoveHelperNodes(); } void QmitkAdaptiveRegionGrowingToolGUI::OnNewToolAssociated(mitk::Tool *tool) { m_RegionGrow3DTool = dynamic_cast(tool); if (m_RegionGrow3DTool.IsNotNull()) { SetInputImageNode(this->m_RegionGrow3DTool->GetReferenceData()); this->m_DataStorage = this->m_RegionGrow3DTool->GetDataStorage(); this->EnableControls(true); // Watch for point added or modified itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded); m_PointSetAddObserverTag = m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand); m_PointSetMoveObserverTag = m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetMoveEvent(), pointAddedCommand); } else { this->EnableControls(false); } } void QmitkAdaptiveRegionGrowingToolGUI::RemoveHelperNodes() { mitk::DataNode::Pointer imageNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (imageNode.IsNotNull()) { m_DataStorage->Remove(imageNode); } mitk::DataNode::Pointer maskedSegmentationNode = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION); if (maskedSegmentationNode.IsNotNull()) { m_DataStorage->Remove(maskedSegmentationNode); } } void QmitkAdaptiveRegionGrowingToolGUI::CreateConnections() { // Connecting GUI components connect((QObject *)(m_Controls.m_pbRunSegmentation), SIGNAL(clicked()), this, SLOT(RunSegmentation())); connect(m_Controls.m_PreviewSlider, SIGNAL(valueChanged(double)), this, SLOT(ChangeLevelWindow(double))); connect((QObject *)(m_Controls.m_pbConfirmSegementation), SIGNAL(clicked()), this, SLOT(ConfirmSegmentation())); connect( m_Controls.m_ThresholdSlider, SIGNAL(maximumValueChanged(double)), this, SLOT(SetUpperThresholdValue(double))); connect( m_Controls.m_ThresholdSlider, SIGNAL(minimumValueChanged(double)), this, SLOT(SetLowerThresholdValue(double))); } void QmitkAdaptiveRegionGrowingToolGUI::SetDataNodeNames(std::string labledSegmentation, std::string binaryImage, std::string surface, std::string maskedSegmentation) { m_NAMEFORLABLEDSEGMENTATIONIMAGE = labledSegmentation; m_NAMEFORBINARYIMAGE = binaryImage; m_NAMEFORSURFACE = surface; m_NAMEFORMASKEDSEGMENTATION = maskedSegmentation; } void QmitkAdaptiveRegionGrowingToolGUI::SetDataStorage(mitk::DataStorage *dataStorage) { m_DataStorage = dataStorage; } -void QmitkAdaptiveRegionGrowingToolGUI::SetMultiWidget(QmitkStdMultiWidget *multiWidget) -{ - m_MultiWidget = multiWidget; -} - void QmitkAdaptiveRegionGrowingToolGUI::SetInputImageNode(mitk::DataNode *node) { m_InputImageNode = node; mitk::Image *inputImage = dynamic_cast(m_InputImageNode->GetData()); if (inputImage) { mitk::ScalarType max = inputImage->GetStatistics()->GetScalarValueMax(); mitk::ScalarType min = inputImage->GetStatistics()->GetScalarValueMin(); m_Controls.m_ThresholdSlider->setMaximum(max); m_Controls.m_ThresholdSlider->setMinimum(min); // Just for initialization m_Controls.m_ThresholdSlider->setMaximumValue(max); m_Controls.m_ThresholdSlider->setMinimumValue(min); } } template static void AccessPixel(mitk::PixelType /*ptype*/, const mitk::Image::Pointer im, mitk::Point3D p, int &val) { mitk::ImagePixelReadAccessor access(im); val = access.GetPixelByWorldCoordinates(p); } void QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded() { if (m_RegionGrow3DTool.IsNull()) return; mitk::DataNode *node = m_RegionGrow3DTool->GetPointSetNode(); if (node != nullptr) { mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { QMessageBox::critical(nullptr, "QmitkAdaptiveRegionGrowingToolGUI", "PointSetNode does not contain a pointset"); return; } m_Controls.m_lblSetSeedpoint->setText(""); mitk::Image *image = dynamic_cast(m_InputImageNode->GetData()); mitk::Point3D seedPoint = pointSet ->GetPointSet( mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))->GetTimeStep()) ->GetPoints() ->ElementAt(0); if (image->GetGeometry()->IsInside(seedPoint)) mitkPixelTypeMultiplex3( AccessPixel, image->GetChannelDescriptor().GetPixelType(), image, seedPoint, m_SeedpointValue) else return; /* In this case the seedpoint is placed e.g. in the lung or bronchialtree * The lowerFactor sets the windowsize depending on the regiongrowing direction */ m_CurrentRGDirectionIsUpwards = true; if (m_SeedpointValue < -500) { m_CurrentRGDirectionIsUpwards = false; } // Initializing the region by the area around the seedpoint m_SeedPointValueMean = 0; itk::Index<3> currentIndex, runningIndex; mitk::ScalarType pixelValues[125]; unsigned int pos(0); image->GetGeometry(0)->WorldToIndex(seedPoint, currentIndex); runningIndex = currentIndex; for (int i = runningIndex[0] - 2; i <= runningIndex[0] + 2; i++) { for (int j = runningIndex[1] - 2; j <= runningIndex[1] + 2; j++) { for (int k = runningIndex[2] - 2; k <= runningIndex[2] + 2; k++) { currentIndex[0] = i; currentIndex[1] = j; currentIndex[2] = k; if (image->GetGeometry()->IsIndexInside(currentIndex)) { int component = 0; m_InputImageNode->GetIntProperty("Image.Displayed Component", component); mitkPixelTypeMultiplex4(mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, nullptr, currentIndex, pixelValues[pos]); pos++; } else { pixelValues[pos] = std::numeric_limits::min(); pos++; } } } } // Now calculation mean of the pixelValues // Now calculation mean of the pixelValues unsigned int numberOfValues(0); for (auto &pixelValue : pixelValues) { if (pixelValue > std::numeric_limits::min()) { m_SeedPointValueMean += pixelValue; numberOfValues++; } } m_SeedPointValueMean = m_SeedPointValueMean / numberOfValues; mitk::ScalarType var = 0; if (numberOfValues > 1) { for (auto &pixelValue : pixelValues) { if (pixelValue > std::numeric_limits::min()) { var += (pixelValue - m_SeedPointValueMean) * (pixelValue - m_SeedPointValueMean); } } var /= numberOfValues - 1; } mitk::ScalarType stdDev = sqrt(var); /* * Here the upper- and lower threshold is calculated: * The windowSize is 20% of the maximum range of the intensity values existing in the current image * If the RG direction is upwards the lower TH is meanSeedValue-0.15*windowSize and upper TH is * meanSeedValue+0.85*windowsSize * if the RG direction is downwards the lower TH is meanSeedValue-0.85*windowSize and upper TH is * meanSeedValue+0.15*windowsSize */ mitk::ScalarType min = image->GetStatistics()->GetScalarValueMin(); mitk::ScalarType max = image->GetStatistics()->GetScalarValueMax(); mitk::ScalarType windowSize = max - min; windowSize = 0.15 * windowSize; if (m_CurrentRGDirectionIsUpwards) { m_LOWERTHRESHOLD = m_SeedPointValueMean - stdDev; m_UPPERTHRESHOLD = m_SeedpointValue + windowSize; if (m_UPPERTHRESHOLD > max) m_UPPERTHRESHOLD = max; m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD); m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD); } else { m_UPPERTHRESHOLD = m_SeedPointValueMean; if (m_SeedpointValue > m_SeedPointValueMean) m_UPPERTHRESHOLD = m_SeedpointValue; m_LOWERTHRESHOLD = m_SeedpointValue - windowSize; if (m_LOWERTHRESHOLD < min) m_LOWERTHRESHOLD = min; m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD); m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD); } } } void QmitkAdaptiveRegionGrowingToolGUI::RunSegmentation() { if (m_InputImageNode.IsNull()) { QMessageBox::information(nullptr, "Adaptive Region Growing functionality", "Please specify the image in Datamanager!"); return; } mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode(); if (node.IsNull()) { QMessageBox::information(nullptr, "Adaptive Region Growing functionality", "Please insert a seed point inside the " "image.\n\nFirst press the \"Define Seed " "Point\" button,\nthen click left mouse " "button inside the image."); return; } // safety if no pointSet or pointSet empty mitk::PointSet::Pointer seedPointSet = dynamic_cast(node->GetData()); if (seedPointSet.IsNull()) { m_Controls.m_pbRunSegmentation->setEnabled(true); QMessageBox::information( nullptr, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point."); return; } int timeStep = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))->GetTimeStep(); if (!(seedPointSet->GetSize(timeStep))) { m_Controls.m_pbRunSegmentation->setEnabled(true); QMessageBox::information( nullptr, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); mitk::PointSet::PointType seedPoint = seedPointSet->GetPointSet(timeStep)->GetPoints()->Begin().Value(); mitk::Image::Pointer orgImage = dynamic_cast(m_InputImageNode->GetData()); if (orgImage.IsNotNull()) { if (orgImage->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(orgImage); timeSelector->SetTimeNr(timeStep); timeSelector->UpdateLargestPossibleRegion(); mitk::Image *timedImage = timeSelector->GetOutput(); AccessByItk_2(timedImage, StartRegionGrowing, timedImage->GetGeometry(), seedPoint); } else if (orgImage->GetDimension() == 3) { // QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); //set the cursor to waiting AccessByItk_2(orgImage, StartRegionGrowing, orgImage->GetGeometry(), seedPoint); // QApplication::restoreOverrideCursor();//reset cursor } else { QApplication::restoreOverrideCursor(); // reset cursor QMessageBox::information( nullptr, "Adaptive Region Growing functionality", "Only images of dimension 3 or 4 can be processed!"); return; } } EnableControls(true); // Segmentation ran successfully, so enable all controls. node->SetVisibility(true); QApplication::restoreOverrideCursor(); // reset cursor } template void QmitkAdaptiveRegionGrowingToolGUI::StartRegionGrowing(itk::Image *itkImage, mitk::BaseGeometry *imageGeometry, mitk::PointSet::PointType seedPoint) { typedef itk::Image InputImageType; typedef typename InputImageType::IndexType IndexType; typedef itk::ConnectedAdaptiveThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); typedef itk::BinaryThresholdImageFilter ThresholdFilterType; typedef itk::MaskImageFilter MaskImageFilterType; if (!imageGeometry->IsInside(seedPoint)) { QApplication::restoreOverrideCursor(); // reset cursor to be able to click ok with the regular mouse cursor QMessageBox::information(nullptr, "Segmentation functionality", "The seed point is outside of the image! Please choose a position inside the image!"); return; } IndexType seedIndex; imageGeometry->WorldToIndex(seedPoint, seedIndex); // convert world coordinates to image indices if (m_SeedpointValue > m_UPPERTHRESHOLD || m_SeedpointValue < m_LOWERTHRESHOLD) { QApplication::restoreOverrideCursor(); // reset cursor to be able to click ok with the regular mouse cursor QMessageBox::information( nullptr, "Segmentation functionality", "The seed point is outside the defined thresholds! Please set a new seed point or adjust the thresholds."); MITK_INFO << "Mean: " << m_SeedPointValueMean; return; } // Setting the direction of the regiongrowing. For dark structures e.g. the lung the regiongrowing // is performed starting at the upper value going to the lower one regionGrower->SetGrowingDirectionIsUpwards(m_CurrentRGDirectionIsUpwards); regionGrower->SetInput(itkImage); regionGrower->AddSeed(seedIndex); // In some cases we have to subtract 1 for the lower threshold and add 1 to the upper. // Otherwise no region growing is done. Maybe a bug in the ConnectiveAdaptiveThresholdFilter regionGrower->SetLower(m_LOWERTHRESHOLD - 1); regionGrower->SetUpper(m_UPPERTHRESHOLD + 1); try { regionGrower->Update(); } catch (itk::ExceptionObject &exc) { QMessageBox errorInfo; errorInfo.setWindowTitle("Adaptive RG Segmentation Functionality"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during region growing!"); errorInfo.setDetailedText(exc.what()); errorInfo.exec(); return; // can't work } catch (...) { QMessageBox::critical(nullptr, "Adaptive RG Segmentation Functionality", "An error occurred during region growing!"); return; } mitk::Image::Pointer resultImage = mitk::ImportItkImage(regionGrower->GetOutput())->Clone(); // initialize slider m_Controls.m_PreviewSlider->setMinimum(m_LOWERTHRESHOLD); mitk::ScalarType max = m_SeedpointValue + resultImage->GetStatistics()->GetScalarValueMax(); if (max < m_UPPERTHRESHOLD) m_Controls.m_PreviewSlider->setMaximum(max); else m_Controls.m_PreviewSlider->setMaximum(m_UPPERTHRESHOLD); this->m_DetectedLeakagePoint = regionGrower->GetLeakagePoint(); if (m_CurrentRGDirectionIsUpwards) { m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean - 1); } else { m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean + 1); } this->m_SliderInitialized = true; // create new node and then delete the old one if there is one mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(resultImage); // set some properties newNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORLABLEDSEGMENTATIONIMAGE)); newNode->SetProperty("helper object", mitk::BoolProperty::New(true)); newNode->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); newNode->SetProperty("layer", mitk::IntProperty::New(1)); newNode->SetProperty("opacity", mitk::FloatProperty::New(0.7)); // delete the old image, if there was one: mitk::DataNode::Pointer binaryNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); m_DataStorage->Remove(binaryNode); // now add result to data tree m_DataStorage->Add(newNode, m_InputImageNode); typename InputImageType::Pointer inputImageItk; mitk::CastToItkImage(resultImage, inputImageItk); // volume rendering preview masking typename ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New(); thresholdFilter->SetInput(inputImageItk); thresholdFilter->SetInsideValue(1); thresholdFilter->SetOutsideValue(0); double sliderVal = this->m_Controls.m_PreviewSlider->value(); if (m_CurrentRGDirectionIsUpwards) { thresholdFilter->SetLowerThreshold(sliderVal); thresholdFilter->SetUpperThreshold(itk::NumericTraits::max()); } else { thresholdFilter->SetLowerThreshold(itk::NumericTraits::min()); thresholdFilter->SetUpperThreshold(sliderVal); } thresholdFilter->SetInPlace(false); typename MaskImageFilterType::Pointer maskFilter = MaskImageFilterType::New(); maskFilter->SetInput(inputImageItk); maskFilter->SetInPlace(false); maskFilter->SetMaskImage(thresholdFilter->GetOutput()); maskFilter->SetOutsideValue(0); maskFilter->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkMask; mitk::CastToMitkImage(maskFilter->GetOutput(), mitkMask); mitk::DataNode::Pointer maskedNode = mitk::DataNode::New(); maskedNode->SetData(mitkMask); // set some properties maskedNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORMASKEDSEGMENTATION)); maskedNode->SetProperty("helper object", mitk::BoolProperty::New(true)); maskedNode->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); maskedNode->SetProperty("layer", mitk::IntProperty::New(1)); maskedNode->SetProperty("opacity", mitk::FloatProperty::New(0.0)); // delete the old image, if there was one: mitk::DataNode::Pointer deprecatedMask = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION); m_DataStorage->Remove(deprecatedMask); // now add result to data tree m_DataStorage->Add(maskedNode, m_InputImageNode); this->InitializeLevelWindow(); if (m_UseVolumeRendering) this->EnableVolumeRendering(true); m_UpdateSuggestedThreshold = true; // reset first stored threshold value // Setting progress to finished mitk::ProgressBar::GetInstance()->Progress(357); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkAdaptiveRegionGrowingToolGUI::InitializeLevelWindow() { // get the preview from the datatree mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, nullptr, "levelwindow"); mitk::ScalarType *level = new mitk::ScalarType(0.0); mitk::ScalarType *window = new mitk::ScalarType(1.0); int upper; if (m_CurrentRGDirectionIsUpwards) { upper = m_UPPERTHRESHOLD - m_SeedpointValue; } else { upper = m_SeedpointValue - m_LOWERTHRESHOLD; } tempLevelWindow.SetRangeMinMax(mitk::ScalarType(0), mitk::ScalarType(upper)); // get the suggested threshold from the detected leakage-point and adjust the slider if (m_CurrentRGDirectionIsUpwards) { this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue); *level = m_UPPERTHRESHOLD - (m_SeedpointValue) + 0.5; } else { this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue); *level = (m_SeedpointValue)-m_LOWERTHRESHOLD + 0.5; } tempLevelWindow.SetLevelWindow(*level, *window); newNode->SetLevelWindow(tempLevelWindow, nullptr, "levelwindow"); // update the widgets mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_SliderInitialized = true; // inquiry need to fix bug#1828 static int lastSliderPosition = 0; if ((this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1) == lastSliderPosition) { this->ChangeLevelWindow(lastSliderPosition); } lastSliderPosition = this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1; - if (m_MultiWidget) - { - this->m_MultiWidget->levelWindowWidget->GetManager()->SetAutoTopMostImage(false); - this->m_MultiWidget->levelWindowWidget->GetManager()->SetLevelWindowProperty( - static_cast(newNode->GetProperty("levelwindow"))); - } - if (m_UseVolumeRendering) this->UpdateVolumeRenderingThreshold((int)(*level + 0.5)); // lower threshold for labeled image } void QmitkAdaptiveRegionGrowingToolGUI::ChangeLevelWindow(double newValue) { if (m_SliderInitialized) { // do nothing, if no preview exists mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, nullptr, "levelwindow"); // get the levelWindow associated with the preview mitk::ScalarType level; // = this->m_UPPERTHRESHOLD - newValue + 0.5; mitk::ScalarType *window = new mitk::ScalarType(1); // adjust the levelwindow according to the position of the slider (newvalue) if (m_CurrentRGDirectionIsUpwards) { level = m_UPPERTHRESHOLD - newValue + 0.5; tempLevelWindow.SetLevelWindow(level, *window); } else { level = newValue - m_LOWERTHRESHOLD + 0.5; tempLevelWindow.SetLevelWindow(level, *window); } newNode->SetLevelWindow(tempLevelWindow, nullptr, "levelwindow"); if (m_UseVolumeRendering) this->UpdateVolumeRenderingThreshold((int)(level - 0.5)); // lower threshold for labeled image newNode->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkAdaptiveRegionGrowingToolGUI::DecreaseSlider() { // moves the slider one step to the left, when the "-"-button is pressed if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->minimum()) { int newValue = this->m_Controls.m_PreviewSlider->value() - 1; this->ChangeLevelWindow(newValue); this->m_Controls.m_PreviewSlider->setValue(newValue); } } void QmitkAdaptiveRegionGrowingToolGUI::IncreaseSlider() { // moves the slider one step to the right, when the "+"-button is pressed if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->maximum()) { int newValue = this->m_Controls.m_PreviewSlider->value() + 1; this->ChangeLevelWindow(newValue); this->m_Controls.m_PreviewSlider->setValue(newValue); } } void QmitkAdaptiveRegionGrowingToolGUI::ConfirmSegmentation() { // get image node if (m_InputImageNode.IsNull()) { QMessageBox::critical(nullptr, "Adaptive region growing functionality", "Please specify the image in Datamanager!"); return; } // get image data mitk::Image::Pointer orgImage = dynamic_cast(m_InputImageNode->GetData()); if (orgImage.IsNull()) { QMessageBox::critical(nullptr, "Adaptive region growing functionality", "No Image found!"); return; } // get labeled segmentation mitk::Image::Pointer labeledSeg = (mitk::Image *)m_DataStorage->GetNamedObject(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (labeledSeg.IsNull()) { QMessageBox::critical(nullptr, "Adaptive region growing functionality", "No Segmentation Preview found!"); return; } mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; QmitkConfirmSegmentationDialog dialog; QString segName = QString::fromStdString(m_RegionGrow3DTool->GetCurrentSegmentationName()); dialog.SetSegmentationName(segName); int result = dialog.exec(); switch (result) { case QmitkConfirmSegmentationDialog::CREATE_NEW_SEGMENTATION: m_RegionGrow3DTool->SetOverwriteExistingSegmentation(false); break; case QmitkConfirmSegmentationDialog::OVERWRITE_SEGMENTATION: m_RegionGrow3DTool->SetOverwriteExistingSegmentation(true); break; case QmitkConfirmSegmentationDialog::CANCEL_SEGMENTATION: return; } mitk::Image::Pointer img = dynamic_cast(newNode->GetData()); AccessByItk(img, ITKThresholding); // disable volume rendering preview after the segmentation node was created this->EnableVolumeRendering(false); newNode->SetVisibility(false); m_Controls.m_cbVolumeRendering->setChecked(false); // TODO disable slider etc... if (m_RegionGrow3DTool.IsNotNull()) { m_RegionGrow3DTool->ConfirmSegmentation(); } } template void QmitkAdaptiveRegionGrowingToolGUI::ITKThresholding(itk::Image *itkImage) { mitk::Image::Pointer originalSegmentation = dynamic_cast(this->m_RegionGrow3DTool->GetTargetSegmentationNode()->GetData()); int timeStep = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))->GetTimeStep(); if (originalSegmentation) { typedef itk::Image InputImageType; typedef itk::Image SegmentationType; // select single 3D volume if we have more than one time step typename SegmentationType::Pointer originalSegmentationInITK = SegmentationType::New(); if (originalSegmentation->GetTimeGeometry()->CountTimeSteps() > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(originalSegmentation); timeSelector->SetTimeNr(timeStep); timeSelector->UpdateLargestPossibleRegion(); CastToItkImage(timeSelector->GetOutput(), originalSegmentationInITK); } else // use original { CastToItkImage(originalSegmentation, originalSegmentationInITK); } // Fill current preiview image in segmentation image originalSegmentationInITK->FillBuffer(0); itk::ImageRegionIterator itOutput(originalSegmentationInITK, originalSegmentationInITK->GetLargestPossibleRegion()); itk::ImageRegionIterator itInput(itkImage, itkImage->GetLargestPossibleRegion()); itOutput.GoToBegin(); itInput.GoToBegin(); // calculate threhold from slider value int currentTreshold = 0; if (m_CurrentRGDirectionIsUpwards) { currentTreshold = m_UPPERTHRESHOLD - m_Controls.m_PreviewSlider->value() + 1; } else { currentTreshold = m_Controls.m_PreviewSlider->value() - m_LOWERTHRESHOLD; } // iterate over image and set pixel in segmentation according to thresholded labeled image while (!itOutput.IsAtEnd() && !itInput.IsAtEnd()) { // Use threshold slider to determine if pixel is set to 1 if (itInput.Value() != 0 && itInput.Value() >= static_cast::PixelType>(currentTreshold)) { itOutput.Set(1); } ++itOutput; ++itInput; } // combine current working segmentation image with our region growing result originalSegmentation->SetVolume((void *)(originalSegmentationInITK->GetPixelContainer()->GetBufferPointer()), timeStep); originalSegmentation->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkAdaptiveRegionGrowingToolGUI::EnableControls(bool enable) { if (m_RegionGrow3DTool.IsNull()) return; // Check if seed point is already set, if not leave RunSegmentation disabled // if even m_DataStorage is nullptr leave node nullptr mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode(); if (node.IsNull()) { this->m_Controls.m_pbRunSegmentation->setEnabled(false); } else { this->m_Controls.m_pbRunSegmentation->setEnabled(enable); } // Check if a segmentation exists, if not leave segmentation dependent disabled. // if even m_DataStorage is nullptr leave node nullptr node = m_DataStorage ? m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE) : nullptr; if (node.IsNull()) { this->m_Controls.m_PreviewSlider->setEnabled(false); this->m_Controls.m_pbConfirmSegementation->setEnabled(false); } else { this->m_Controls.m_PreviewSlider->setEnabled(enable); this->m_Controls.m_pbConfirmSegementation->setEnabled(enable); } this->m_Controls.m_cbVolumeRendering->setEnabled(enable); } void QmitkAdaptiveRegionGrowingToolGUI::EnableVolumeRendering(bool enable) { mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION); if (node.IsNull()) return; - if (m_MultiWidget) - m_MultiWidget->SetWidgetPlanesVisibility(!enable); - if (enable) { node->SetBoolProperty("volumerendering", enable); node->SetBoolProperty("volumerendering.uselod", true); } else { node->SetBoolProperty("volumerendering", enable); } double val = this->m_Controls.m_PreviewSlider->value(); this->ChangeLevelWindow(val); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkAdaptiveRegionGrowingToolGUI::UpdateVolumeRenderingThreshold(int) { typedef short PixelType; typedef itk::Image InputImageType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; typedef itk::MaskImageFilter MaskImageFilterType; mitk::DataNode::Pointer grownImageNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); mitk::Image::Pointer grownImage = dynamic_cast(grownImageNode->GetData()); if (!grownImage) { MITK_ERROR << "Missing data node for labeled segmentation image."; return; } InputImageType::Pointer itkGrownImage; mitk::CastToItkImage(grownImage, itkGrownImage); ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New(); thresholdFilter->SetInput(itkGrownImage); thresholdFilter->SetInPlace(false); double sliderVal = this->m_Controls.m_PreviewSlider->value(); PixelType threshold = itk::NumericTraits::min(); if (m_CurrentRGDirectionIsUpwards) { threshold = static_cast(m_UPPERTHRESHOLD - sliderVal + 0.5); thresholdFilter->SetLowerThreshold(threshold); thresholdFilter->SetUpperThreshold(itk::NumericTraits::max()); } else { threshold = sliderVal - m_LOWERTHRESHOLD + 0.5; thresholdFilter->SetLowerThreshold(itk::NumericTraits::min()); thresholdFilter->SetUpperThreshold(threshold); } thresholdFilter->UpdateLargestPossibleRegion(); MaskImageFilterType::Pointer maskFilter = MaskImageFilterType::New(); maskFilter->SetInput(itkGrownImage); maskFilter->SetInPlace(false); maskFilter->SetMaskImage(thresholdFilter->GetOutput()); maskFilter->SetOutsideValue(0); maskFilter->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkMaskedImage; mitk::CastToMitkImage(maskFilter->GetOutput(), mitkMaskedImage); mitk::DataNode::Pointer maskNode = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION); maskNode->SetData(mitkMaskedImage); } void QmitkAdaptiveRegionGrowingToolGUI::UseVolumeRendering(bool on) { m_UseVolumeRendering = on; this->EnableVolumeRendering(on); } void QmitkAdaptiveRegionGrowingToolGUI::SetLowerThresholdValue(double lowerThreshold) { m_LOWERTHRESHOLD = lowerThreshold; } void QmitkAdaptiveRegionGrowingToolGUI::SetUpperThresholdValue(double upperThreshold) { m_UPPERTHRESHOLD = upperThreshold; } void QmitkAdaptiveRegionGrowingToolGUI::Deactivated() { // make the segmentation preview node invisible mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (node.IsNotNull()) { node->SetVisibility(false); } // disable volume rendering preview after the segmentation node was created this->EnableVolumeRendering(false); m_Controls.m_cbVolumeRendering->setChecked(false); } void QmitkAdaptiveRegionGrowingToolGUI::Activated() { } diff --git a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.h index 4177033e7e..6fdbfc16f2 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.h @@ -1,232 +1,222 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITK_QmitkAdaptiveRegionGrowingToolGUI_H #define QMITK_QmitkAdaptiveRegionGrowingToolGUI_H #include "itkImage.h" #include "mitkDataStorage.h" #include "mitkGeometry3D.h" #include "mitkPointSet.h" #include "qwidget.h" #include "ui_QmitkAdaptiveRegionGrowingToolGUIControls.h" #include #include "QmitkToolGUI.h" #include "mitkAdaptiveRegionGrowingTool.h" -class QmitkStdMultiWidget; class DataNode; class QmitkAdaptiveRegionGrowingToolGUIControls; /*! * * \brief QmitkAdaptiveRegionGrowingToolGUI * * Adaptive Region Growing View class of the segmentation. * */ class MITKSEGMENTATIONUI_EXPORT QmitkAdaptiveRegionGrowingToolGUI : public QmitkToolGUI { Q_OBJECT public: /** * @brief mitkClassMacro */ mitkClassMacro(QmitkAdaptiveRegionGrowingToolGUI, QmitkToolGUI); itkFactorylessNewMacro(Self) itkCloneMacro(Self) QmitkAdaptiveRegionGrowingToolGUI(QWidget *parent = nullptr); /** \brief Method to create the connections for the component. This Method is obligatory even if no connections is * needed*/ virtual void CreateConnections(); ///** \brief Method to set the default data storage.*/ virtual void SetDataStorage(mitk::DataStorage *dataStorage); - /** - * @brief Method to set the used multiwidget. - * @param multiWidget - */ - void SetMultiWidget(QmitkStdMultiWidget *multiWidget); - /** * @brief Method to set the name of a data node. * @param labledSegmentation Name of the labeled segmentation * @param binaryImage Name of the binary image * @param surface Name of the surface */ void SetDataNodeNames(std::string labledSegmentation, std::string binaryImage, /*std::string vesselTree,*/ std::string surface, std::string maskedSegmentation); /** * @brief Method to enable/disable controls for region growing * * This method checks if a seed point is set and a segmentation exists. * @param enable/disable controls */ void EnableControls(bool enable); /** * @brief Method to set the input image node * @param data node */ void SetInputImageNode(mitk::DataNode *node); void Deactivated(); void Activated(); /** * @brief The created GUI from the .ui-File. This Attribute is obligatory */ Ui::QmitkAdaptiveRegionGrowingToolGUIControls m_Controls; protected slots: /** * @brief Method to start the segmentation * * This method is called, when the "Start Segmentation" button is clicked. */ void RunSegmentation(); /** * @brief Method to change the level window * * This method is called, when the level window slider is changed via the slider in the control widget * @param new value */ void ChangeLevelWindow(double newValue); /** * @brief Method to increase the preview slider * * This method is called, when the + button is clicked and increases the value by 1 */ void IncreaseSlider(); /** * @brief Method to decrease the preview slider * * This method is called, when the - button is clicked and decreases the value by 1 */ void DecreaseSlider(); /** * @brief Method to confirm the preview segmentation * * This method is called, when the "Confirm Segmentation" button is clicked. */ void ConfirmSegmentation(); /** * @brief Method to switch the volume rendering on/off * @param on/off */ void UseVolumeRendering(bool on); /** * @brief Method to set the lower threshold * * This method is called, when the minimum threshold slider has changed * @param lower threshold */ void SetLowerThresholdValue(double lowerThreshold); /** * @brief Method to set upper threshold * * This Method is called, when the maximum threshold slider has changed * @param upper threshold */ void SetUpperThresholdValue(double upperThreshold); /** * @brief Method to determine which tool to activate * * This method listens to the tool manager and activates this tool if requested otherwise disables this view */ void OnNewToolAssociated(mitk::Tool *); protected: mitk::AdaptiveRegionGrowingTool::Pointer m_RegionGrow3DTool; /** \brief Destructor. */ ~QmitkAdaptiveRegionGrowingToolGUI() override; - // Pointer to the main widget to be able to reach the renderer - QmitkStdMultiWidget *m_MultiWidget; - mitk::DataStorage *m_DataStorage; mitk::DataNode::Pointer m_InputImageNode; /** * @brief Method to calculate parameter settings, when a seed point is set */ void OnPointAdded(); private: std::string m_NAMEFORORGIMAGE; std::string m_NAMEFORLABLEDSEGMENTATIONIMAGE; std::string m_NAMEFORBINARYIMAGE; std::string m_NAMEFORSURFACE; std::string m_NAMEFORMASKEDSEGMENTATION; mitk::ScalarType m_LOWERTHRESHOLD; // Hounsfield value mitk::ScalarType m_UPPERTHRESHOLD; // Hounsfield value mitk::ScalarType m_SeedPointValueMean; void RemoveHelperNodes(); int m_DetectedLeakagePoint; bool m_CurrentRGDirectionIsUpwards; // defines fixed threshold (true = LOWERTHRESHOLD fixed, false = UPPERTHRESHOLD // fixed) int m_SeedpointValue; bool m_SliderInitialized; bool m_UseVolumeRendering; bool m_UpdateSuggestedThreshold; float m_SuggestedThValue; long m_PointSetAddObserverTag; long m_PointSetMoveObserverTag; template void StartRegionGrowing(itk::Image *itkImage, mitk::BaseGeometry *imageGeometry, mitk::PointSet::PointType seedPoint); template void ITKThresholding(itk::Image *inputImage); void InitializeLevelWindow(); void EnableVolumeRendering(bool enable); void UpdateVolumeRenderingThreshold(int thValue); }; #endif diff --git a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h index 89afbcd99a..8d9890d42c 100644 --- a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h +++ b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPart.h @@ -1,191 +1,194 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIRENDERWINDOWPART_H #define MITKIRENDERWINDOWPART_H #include #include #include #include +#include #include #include #include class QmitkRenderWindow; namespace mitk { struct IRenderingManager; class SliceNavigationController; /** * \ingroup org_mitk_gui_common * * \brief Interface for a MITK Workbench Part providing a render window. * * This interface allows generic access to Workbench parts which provide some * kind of render window. The interface is intended to be implemented by * subclasses of berry::IWorkbenchPart. Usually, the interface is implemented * by a Workbench editor. * * A IRenderWindowPart provides zero or more QmitkRenderWindow instances which can * be controlled via this interface. QmitkRenderWindow instances have an associated - * \e id, which is implementation specific. However, implementations should consider - * to use one of the following ids for certain QmitkRenderWindow instances to maximize - * reusability (they are free to map multiple ids to one QmitkRenderWindow internally): - *
    - *
  • axial
  • - *
  • sagittal
  • - *
  • coronal
  • - *
  • 3d
  • - *
+ * \e id, which is implementation specific. + * Additionally the defined values AXIAL, SAGITTAL, CORONAL, THREE_D from mitk::BaseRenderer + * can be used to retrieve a specific QmitkRenderWindow. * * \see ILinkedRenderWindowPart * \see IRenderWindowPartListener * \see QmitkAbstractRenderEditor */ struct MITK_GUI_COMMON_PLUGIN IRenderWindowPart { static const QString DECORATION_BORDER; // = "border" static const QString DECORATION_LOGO; // = "logo" static const QString DECORATION_MENU; // = "menu" static const QString DECORATION_BACKGROUND; // = "background" static const QString DECORATION_CORNER_ANNOTATION; // = "corner annotation" virtual ~IRenderWindowPart(); /** * Get the currently active (focused) render window. * Focus handling is implementation specific. * * \return The active QmitkRenderWindow instance; nullptr * if no render window is active. */ virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const = 0; /** * Get all render windows with their ids. * * \return A hash map mapping the render window id to the QmitkRenderWindow instance. */ virtual QHash GetQmitkRenderWindows() const = 0; /** * Get a render window with a specific id. * * \param id The render window id. * \return The QmitkRenderWindow instance for id */ virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const = 0; + /** + * Get a render window with a specific view direction. + * + * \param viewDirection The render window view direction. + * \return The QmitkRenderWindow instance for viewDirection + */ + virtual QmitkRenderWindow* GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const = 0; + /** * Get the rendering manager used by this render window part. * * \return The current IRenderingManager instance or nullptr * if no rendering manager is used. */ virtual mitk::IRenderingManager* GetRenderingManager() const = 0; /** * Request an update of all render windows. * * \param requestType Specifies the type of render windows for which an update * will be requested. */ virtual void RequestUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) = 0; /** * Force an immediate update of all render windows. * * \param requestType Specifies the type of render windows for which an immediate update * will be requested. */ virtual void ForceImmediateUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL) = 0; /** * Get the SliceNavigationController for controlling time positions. * * \return A SliceNavigationController if the render window supports this * operation; otherwise returns nullptr. */ virtual mitk::SliceNavigationController* GetTimeNavigationController() const = 0; /** * Get the selected position in the render window with id id * or in the active render window if id is nullptr. * * \param id The render window id. * \return The currently selected position in world coordinates. */ virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const = 0; /** * Set the selected position in the render window with id id * or in the active render window if id is nullptr. * * \param pos The position in world coordinates which should be selected. * \param id The render window id in which the selection should take place. */ virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) = 0; /** * Enable \e decorations like colored borders, menu widgets, logos, text annotations, etc. * * Decorations are implementation specific. A set of standardized decoration names is listed * in GetDecorations(). * * \param enable If true enable the decorations specified in decorations, * otherwise disable them. * \param decorations A list of decoration names. If empty, all supported decorations are affected. * * \see GetDecorations() */ virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) = 0; /** * Return if a specific decoration is enabled. * * \return true if the decoration is enabled, false if it is disabled * or unknown. * * \see GetDecorations() */ virtual bool IsDecorationEnabled(const QString& decoration) const = 0; /** * Get a list of supported decorations. * * The following decoration names are standardized and should not be used for other decoration types: *
    *
  • \e DECORATION_BORDER Any border decorations like colored rectangles, etc. *
  • \e DECORATION_MENU Menus associated with render windows *
  • \e DECORATION_BACKGROUND All kinds of backgrounds (patterns, gradients, etc.) except for solid colored backgrounds *
  • \e DECORATION_LOGO Any kind of logo overlayed on the rendered scene *
* * \return A list of supported decoration names. */ virtual QStringList GetDecorations() const = 0; }; } Q_DECLARE_INTERFACE(mitk::IRenderWindowPart, "org.mitk.ui.IRenderWindowPart") #endif // MITKIRENDERWINDOWPART_H diff --git a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.cpp b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.cpp old mode 100755 new mode 100644 index fe77299439..c723116ce4 --- a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.cpp +++ b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.cpp @@ -1,379 +1,377 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkFunctionality.h" #include "internal/QmitkFunctionalityUtil.h" #include "internal/QmitkCommonLegacyActivator.h" // other includes #include // mitk Includes #include #include // berry Includes #include #include #include #include // Qmitk Includes #include // Qt Includes #include #include #include #include QmitkFunctionality::QmitkFunctionality() : m_Parent(nullptr) , m_Active(false) , m_Visible(false) , m_SelectionProvider(nullptr) , m_DataStorageServiceTracker(QmitkCommonLegacyActivator::GetContext()) , m_HandlesMultipleDataStorages(false) , m_InDataStorageChanged(false) { m_DataStorageServiceTracker.open(); } void QmitkFunctionality::SetHandleMultipleDataStorages(bool multiple) { m_HandlesMultipleDataStorages = multiple; } bool QmitkFunctionality::HandlesMultipleDataStorages() const { return m_HandlesMultipleDataStorages; } mitk::DataStorage::Pointer QmitkFunctionality::GetDataStorage() const { mitk::IDataStorageService* service = m_DataStorageServiceTracker.getService(); if (service != nullptr) { if(m_HandlesMultipleDataStorages) return service->GetActiveDataStorage()->GetDataStorage(); else return service->GetDefaultDataStorage()->GetDataStorage(); } return nullptr; } mitk::DataStorage::Pointer QmitkFunctionality::GetDefaultDataStorage() const { mitk::IDataStorageService* service = m_DataStorageServiceTracker.getService(); if (service != nullptr) { return service->GetDefaultDataStorage()->GetDataStorage(); } return nullptr; } mitk::IDataStorageReference::Pointer QmitkFunctionality::GetDataStorageReference() const { mitk::IDataStorageService* dsService = m_DataStorageServiceTracker.getService(); if (dsService != nullptr) { return dsService->GetDataStorage(); } return mitk::IDataStorageReference::Pointer(nullptr); } void QmitkFunctionality::CreatePartControl(QWidget* parent) { // scrollArea QScrollArea* scrollArea = new QScrollArea; //QVBoxLayout* scrollAreaLayout = new QVBoxLayout(scrollArea); scrollArea->setFrameShadow(QFrame::Plain); scrollArea->setFrameShape(QFrame::NoFrame); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); // m_Parent m_Parent = new QWidget; //m_Parent->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); this->CreateQtPartControl(m_Parent); //scrollAreaLayout->addWidget(m_Parent); //scrollArea->setLayout(scrollAreaLayout); // set the widget now scrollArea->setWidgetResizable(true); scrollArea->setWidget(m_Parent); // add the scroll area to the real parent (the view tabbar) QWidget* parentQWidget = static_cast(parent); QVBoxLayout* parentLayout = new QVBoxLayout(parentQWidget); parentLayout->setMargin(0); parentLayout->setSpacing(0); parentLayout->addWidget(scrollArea); // finally set the layout containing the scroll area to the parent widget (= show it) parentQWidget->setLayout(parentLayout); this->AfterCreateQtPartControl(); } void QmitkFunctionality::AfterCreateQtPartControl() { // REGISTER DATASTORAGE LISTENER this->GetDefaultDataStorage()->AddNodeEvent.AddListener( mitk::MessageDelegate1 ( this, &QmitkFunctionality::NodeAddedProxy ) ); this->GetDefaultDataStorage()->ChangedNodeEvent.AddListener( mitk::MessageDelegate1 ( this, &QmitkFunctionality::NodeChangedProxy ) ); this->GetDefaultDataStorage()->RemoveNodeEvent.AddListener( mitk::MessageDelegate1 ( this, &QmitkFunctionality::NodeRemovedProxy ) ); // REGISTER PREFERENCES LISTENER berry::IBerryPreferences::Pointer prefs = this->GetPreferences().Cast(); if(prefs.IsNotNull()) prefs->OnChanged.AddListener(berry::MessageDelegate1(this, &QmitkFunctionality::OnPreferencesChanged)); // REGISTER FOR WORKBENCH SELECTION EVENTS m_BlueBerrySelectionListener.reset(new berry::SelectionChangedAdapter( this, &QmitkFunctionality::BlueBerrySelectionChanged) ); this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddPostSelectionListener( /*"org.mitk.views.datamanager",*/ m_BlueBerrySelectionListener.data()); // REGISTER A SELECTION PROVIDER QmitkFunctionalitySelectionProvider::Pointer _SelectionProvider( new QmitkFunctionalitySelectionProvider(this)); m_SelectionProvider = _SelectionProvider.GetPointer(); this->GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(m_SelectionProvider)); // EMULATE INITIAL SELECTION EVENTS - // by default a a multi widget is always available - this->StdMultiWidgetAvailable(*this->GetActiveStdMultiWidget()); + // by default a multi widget is always available + this->MultiWidgetAvailable(*this->GetActiveMultiWidget()); // send datamanager selection this->OnSelectionChanged(this->GetDataManagerSelection()); // send preferences changed event this->OnPreferencesChanged(this->GetPreferences().Cast().GetPointer()); } void QmitkFunctionality::ClosePart() { } void QmitkFunctionality::ClosePartProxy() { this->GetDefaultDataStorage()->AddNodeEvent.RemoveListener( mitk::MessageDelegate1 ( this, &QmitkFunctionality::NodeAddedProxy ) ); this->GetDefaultDataStorage()->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1 ( this, &QmitkFunctionality::NodeRemovedProxy) ); this->GetDefaultDataStorage()->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1 ( this, &QmitkFunctionality::NodeChangedProxy ) ); berry::IBerryPreferences::Pointer prefs = this->GetPreferences().Cast(); if(prefs.IsNotNull()) { prefs->OnChanged.RemoveListener(berry::MessageDelegate1(this, &QmitkFunctionality::OnPreferencesChanged)); // flush the preferences here (disabled, everyone should flush them by themselves at the right moment) // prefs->Flush(); } // REMOVE SELECTION PROVIDER this->GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(nullptr)); berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); if(s) { s->RemovePostSelectionListener(m_BlueBerrySelectionListener.data()); } this->ClosePart(); } QmitkFunctionality::~QmitkFunctionality() { this->Register(); this->ClosePartProxy(); this->UnRegister(false); m_DataStorageServiceTracker.close(); } void QmitkFunctionality::OnPreferencesChanged( const berry::IBerryPreferences* ) { } void QmitkFunctionality::BlueBerrySelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection) { if(sourcepart.IsNull() || sourcepart->GetSite()->GetId() != "org.mitk.views.datamanager") return; mitk::DataNodeSelection::ConstPointer _DataNodeSelection = selection.Cast(); this->OnSelectionChanged(this->DataNodeSelectionToVector(_DataNodeSelection)); } bool QmitkFunctionality::IsVisible() const { return m_Visible; } void QmitkFunctionality::SetFocus() { } void QmitkFunctionality::Activated() { } void QmitkFunctionality::Deactivated() { } -void QmitkFunctionality::StdMultiWidgetAvailable( QmitkStdMultiWidget& /*stdMultiWidget*/ ) +void QmitkFunctionality::MultiWidgetAvailable( QmitkAbstractMultiWidget& /*multiWidget*/ ) { } -void QmitkFunctionality::StdMultiWidgetNotAvailable() +void QmitkFunctionality::MultiWidgetNotAvailable() { } void QmitkFunctionality::DataStorageChanged() { } -QmitkStdMultiWidget* QmitkFunctionality::GetActiveStdMultiWidget( bool reCreateWidget ) +QmitkAbstractMultiWidget* QmitkFunctionality::GetActiveMultiWidget( bool reCreateWidget ) { - QmitkStdMultiWidget* activeStdMultiWidget = nullptr; + QmitkAbstractMultiWidget* activeMultiWidget = nullptr; berry::IEditorPart::Pointer editor = this->GetSite()->GetPage()->GetActiveEditor(); - if (reCreateWidget - || editor.Cast().IsNull() - ) + if (reCreateWidget || editor.Cast().IsNull()) { mitk::DataStorageEditorInput::Pointer editorInput( new mitk::DataStorageEditorInput( this->GetDataStorageReference() )); // open a new multi-widget editor, but do not give it the focus berry::IEditorPart::Pointer editor = this->GetSite()->GetPage()->OpenEditor(editorInput, QmitkStdMultiWidgetEditor::EDITOR_ID, false, berry::IWorkbenchPage::MATCH_ID); - activeStdMultiWidget = editor.Cast()->GetStdMultiWidget(); + activeMultiWidget = editor.Cast()->GetMultiWidget(); } else if (editor.Cast().IsNotNull()) { - activeStdMultiWidget = editor.Cast()->GetStdMultiWidget(); + activeMultiWidget = editor.Cast()->GetMultiWidget(); } - return activeStdMultiWidget; + return activeMultiWidget; } void QmitkFunctionality::HandleException( const char* str, QWidget* parent, bool showDialog ) const { //itkGenericOutputMacro( << "Exception caught: " << str ); MITK_ERROR << str; if ( showDialog ) { QMessageBox::critical ( parent, "Exception caught!", str ); } } void QmitkFunctionality::HandleException( std::exception& e, QWidget* parent, bool showDialog ) const { HandleException( e.what(), parent, showDialog ); } -void QmitkFunctionality::StdMultiWidgetClosed( QmitkStdMultiWidget& /*stdMultiWidget*/ ) +void QmitkFunctionality::MultiWidgetClosed( QmitkAbstractMultiWidget& /*multiWidget*/ ) { } void QmitkFunctionality::WaitCursorOn() { QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); } void QmitkFunctionality::BusyCursorOn() { QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) ); } void QmitkFunctionality::WaitCursorOff() { this->RestoreOverrideCursor(); } void QmitkFunctionality::BusyCursorOff() { this->RestoreOverrideCursor(); } void QmitkFunctionality::RestoreOverrideCursor() { QApplication::restoreOverrideCursor(); } berry::IPreferences::Pointer QmitkFunctionality::GetPreferences() const { berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); // const_cast workaround for bad programming: const uncorrectness this->GetViewSite() should be const QString id = "/" + (const_cast(this))->GetViewSite()->GetId(); return prefService != nullptr ? prefService->GetSystemPreferences()->Node(id): berry::IPreferences::Pointer(nullptr); } void QmitkFunctionality::Visible() { } void QmitkFunctionality::Hidden() { } bool QmitkFunctionality::IsExclusiveFunctionality() const { return true; } void QmitkFunctionality::SetVisible( bool visible ) { m_Visible = visible; } void QmitkFunctionality::SetActivated( bool activated ) { m_Active = activated; } bool QmitkFunctionality::IsActivated() const { return m_Active; } diff --git a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h index 8fe7aff1c4..1ddd364998 100755 --- a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h +++ b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h @@ -1,400 +1,400 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKFUNCTIONALITY_H_ #define QMITKFUNCTIONALITY_H_ //# blueberry stuff #include #include #include #include //# mitk stuff #include #include "mitkDataNodeSelection.h" #include #include #include -#include +#include // CTK Includes #include //# forward declarations namespace mitk { class DataNode; struct IDataStorageService; } namespace berry { struct IBerryPreferences; } class QmitkFunctionalitySelectionProvider; /// /// \ingroup org_mitk_gui_qt_common_legacy /// /// \class QmitkFunctionality /// /// \brief The base class of all MITK related blueberry views (~ in the old version of MITK, this was called "Functionality") /// /// QmitkFunctionality provides several convenience methods that eases the introduction of a new view: /// ///
    ///
  1. Access to the DataStorage (~ the shared data repository) -///
  2. Access to the StdMultiWidget (the 2x2 RenderWindow arrangement) +///
  3. Access to the MultiWidget ///
  4. Access to and update notification for the functionality/view preferences ///
  5. Access to and update notification for the current DataNode selection / to DataNode selection events send through the SelectionService ///
  6. Methods to send DataNode selections through the SelectionService ///
  7. Some events for unproblematic inter-View communication (e.g. when to add/remove interactors) ///
  8. Some minor important convenience methods (like changing the mouse cursor/exception handling) ///
/// /// Please use the Activated/Deactivated method to add/remove interactors, disabling multiwidget crosshair or anything which may /// "affect" other functionalities. For further reading please have a look at QmitkFunctionality::IsExclusiveFunctionality(). /// class MITK_QT_COMMON_LEGACY QmitkFunctionality : public berry::QtViewPart { //# public virtual methods which can be overwritten public: /// /// Creates smartpointer typedefs /// berryObjectMacro(QmitkFunctionality); /// /// Nothing to do in the standard ctor. Initiliaze your GUI in CreateQtPartControl(QWidget*) /// \see berry::QtViewPart::CreateQtPartControl(QWidget*) /// QmitkFunctionality(); /// /// Disconnects all standard event listeners /// ~QmitkFunctionality() override; /// /// Called, when the WorkbenchPart gets closed /// by the user directly or by closing the whole /// app (e.g. for removing event listeners) /// virtual void ClosePart(); /// /// Called when the selection in the workbench changed /// virtual void OnSelectionChanged(std::vector /*nodes*/); /// /// Called when the preferences object of this view changed. /// \see GetPreferences() /// virtual void OnPreferencesChanged(const berry::IBerryPreferences*); /// /// Make this view manage multiple DataStorage. If set to true GetDataStorage() /// will return the currently active DataStorage (and not the default one). /// \see GetDataStorage() /// void SetHandleMultipleDataStorages(bool multiple); /// /// \return true if this view handles multiple DataStorages, false otherwise /// bool HandlesMultipleDataStorages() const; /// - /// Called when a StdMultiWidget is available. Should not be used anymore, see GetActiveStdMultiWidget() - /// \see GetActiveStdMultiWidget() + /// Called when a MultiWidget is available. Should not be used anymore, see GetActiveMultiWidget() + /// \see GetActiveMultiWidget() /// - virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget); + virtual void MultiWidgetAvailable(QmitkAbstractMultiWidget& multiWidget); /// - /// Called when a StdMultiWidget is available. Should not be used anymore, see GetActiveStdMultiWidget() - /// \see GetActiveStdMultiWidget() + /// Called when a MultiWidget is available. Should not be used anymore, see GetActiveMultiWidget() + /// \see GetActiveMultiWidget() /// - virtual void StdMultiWidgetClosed(QmitkStdMultiWidget& stdMultiWidget); + virtual void MultiWidgetClosed(QmitkAbstractMultiWidget& multiWidget); /// - /// Called when no StdMultiWidget is available anymore. Should not be used anymore, see GetActiveStdMultiWidget() - /// \see GetActiveStdMultiWidget() + /// Called when no MultiWidget is available anymore. Should not be used anymore, see GetActiveMultiWidget() + /// \see GetActiveMultiWidget() /// - virtual void StdMultiWidgetNotAvailable(); + virtual void MultiWidgetNotAvailable(); /// /// Only called when IsExclusiveFunctionality() returns true. /// \see IsExclusiveFunctionality() /// virtual void Activated(); /// /// \return true if this view is currently activated, false otherwise /// bool IsActivated() const; /// /// Only called when IsExclusiveFunctionality() returns true. /// \see IsExclusiveFunctionality() /// virtual void Deactivated(); /// - /// Some functionalities need to add special interactors, removes the crosshair from the stdmultiwidget, etc. + /// Some functionalities need to add special interactors, removes the crosshair from the multiwidget, etc. /// In this case the functionality has to tidy up when changing to another functionality /// which also wants to change the "default configuration". In the old Qt3-based /// version of MITK, two functionalities could never be opened at the same time so that the /// methods Activated() and Deactivated() were the right place for the functionalitites to /// add/remove their interactors, etc. This is still true for the new MITK Workbench, /// but as there can be several functionalities visible at the same time, the behaviour concerning /// when Activated() and Deactivated() are called has changed: /// /// 1. Activated() and Deactivated() are only called if IsExclusiveFunctionality() returns true /// /// 2. If only one standalone functionality is or becomes visible, Activated() will be called on that functionality /// /// 3. If two or more standalone functionalities are visible, /// Activated() will be called on the functionality that receives focus, Deactivated() will be called /// on the one that looses focus, gets hidden or closed /// /// /// As a consequence of 1. if you overwrite IsExclusiveFunctionality() and let it return false, you /// signalize the MITK Workbench that this functionality does nothing to the "default configuration" /// and can easily be visible while other functionalities are also visible. /// /// By default the method returns true. /// /// \return true if this functionality is meant to work as a standalone view, false otherwise /// virtual bool IsExclusiveFunctionality() const; /// /// Informs other parts of the workbench that node is selected via the blueberry selection service. /// void FireNodeSelected(mitk::DataNode* node); /// /// Informs other parts of the workbench that the nodes are selected via the blueberry selection service. /// void FireNodesSelected(std::vector nodes); /// /// Called when this functionality becomes visible ( no matter what IsExclusiveFunctionality() returns ) /// virtual void Visible(); /// /// \return true if this view is currently visible, false otherwise /// bool IsVisible() const; /// /// Called when this functionality is hidden ( no matter what IsExclusiveFunctionality() returns ) /// virtual void Hidden(); //# protected virtual methods which can be overwritten protected: /// /// Called when a DataStorage Add event was thrown. May be reimplemented /// by deriving classes. /// virtual void NodeAdded(const mitk::DataNode* node); /// /// Called when a DataStorage Changed event was thrown. May be reimplemented /// by deriving classes. /// virtual void NodeChanged(const mitk::DataNode* /*node*/); /// /// Called when a DataStorage Remove event was thrown. May be reimplemented /// by deriving classes. /// virtual void NodeRemoved(const mitk::DataNode* node); /// /// Called when a DataStorage add *or* remove *or* change event was thrown. May be reimplemented /// by deriving classes. /// virtual void DataStorageChanged(); /// /// \return the selection of the currently active part of the workbench or an empty vector /// if nothing is selected /// std::vector GetCurrentSelection() const; /// /// Returns the current selection made in the datamanager bundle or an empty vector /// if nothing`s selected or if the bundle does not exist /// std::vector GetDataManagerSelection() const; /// /// Returns the Preferences object for this Functionality. /// Important: When refering to this preferences, e.g. in a PreferencePage: The ID /// for this preferences object is "/", e.g. "/org.mitk.views.datamanager" /// berry::IPreferences::Pointer GetPreferences() const; /// /// Returns the default or the currently active DataStorage if m_HandlesMultipleDataStorages /// is set to true /// \see SetHandleMultipleDataStorages(bool) /// \see HandlesMultipleDataStorages() /// mitk::DataStorage::Pointer GetDataStorage() const; /// /// \return always returns the default DataStorage /// mitk::DataStorage::Pointer GetDefaultDataStorage() const; mitk::IDataStorageReference::Pointer GetDataStorageReference() const; /// - /// Returns the default and active StdMultiWidget. - /// \param reCreateWidget a boolean flag to en-/disable the attept to re-create the StdWidget - /// If there is not StdMultiWidget yet a new one is + /// Returns the default and active MultiWidget. + /// \param reCreateWidget a boolean flag to en-/disable the attempt to re-create the StdWidget + /// If there is not MultiWidget yet a new one is /// created in this method when called with default parameter! /// - QmitkStdMultiWidget* GetActiveStdMultiWidget( bool reCreateWidget = true); + QmitkAbstractMultiWidget* GetActiveMultiWidget( bool reCreateWidget = true); /// /// Outputs an error message to the console and displays a message box containing /// the exception description. /// \param e the exception which should be handled /// \param showDialog controls, whether additionally a message box should be /// displayed to inform the user that something went wrong /// void HandleException( std::exception& e, QWidget* parent = nullptr, bool showDialog = true ) const; /// /// Calls HandleException ( std::exception&, QWidget*, bool ) internally /// \see HandleException ( std::exception&, QWidget*, bool ) /// void HandleException( const char* str, QWidget* parent = nullptr, bool showDialog = true ) const; /// /// Convenient method to set and reset a wait cursor ("hourglass") /// void WaitCursorOn(); /// /// Convenient method to restore the standard cursor /// void WaitCursorOff(); /// /// Convenient method to set and reset a busy cursor /// void BusyCursorOn(); /// /// Convenient method to restore the standard cursor /// void BusyCursorOff(); /// /// Convenient method to restore the standard cursor /// void RestoreOverrideCursor(); //# other public methods which should not be overwritten public: /// /// Creates a scroll area for this view and calls CreateQtPartControl then /// void CreatePartControl(QWidget* parent) override; /// /// Called when this view receives the focus. Same as Activated() /// \see Activated() /// void SetFocus() override; /// /// Called when a DataStorage Add Event was thrown. Sets /// m_InDataStorageChanged to true and calls NodeAdded afterwards. /// \see m_InDataStorageChanged /// void NodeAddedProxy(const mitk::DataNode* node); /// /// Called when a DataStorage remove event was thrown. Sets /// m_InDataStorageChanged to true and calls NodeRemoved afterwards. /// \see m_InDataStorageChanged /// void NodeRemovedProxy(const mitk::DataNode* node); /// /// Called when a DataStorage changed event was thrown. Sets /// m_InDataStorageChanged to true and calls NodeChanged afterwards. /// \see m_InDataStorageChanged /// void NodeChangedProxy(const mitk::DataNode* node); /// /// Toggles the visible flag m_Visible /// void SetVisible(bool visible); /// /// Toggles the activated flag m_Activated /// void SetActivated(bool activated); /// /// Called, when the WorkbenchPart gets closed for removing event listeners /// Internally this method calls ClosePart after it removed the listeners registered /// by QmitkFunctionality. By having this proxy method the user does not have to /// call QmitkFunctionality::ClosePart() when overwriting ClosePart() /// void ClosePartProxy(); //# other protected methods which should not be overwritten (or which are deprecated) protected: /// /// Called immediately after CreateQtPartControl(). /// Here standard event listeners for a QmitkFunctionality are registered /// void AfterCreateQtPartControl(); /// /// code to activate the last visible functionality /// void ActivateLastVisibleFunctionality(); /// /// reactions to selection events from data manager (and potential other senders) /// void BlueBerrySelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection); /// /// Converts a mitk::DataNodeSelection to a std::vector (possibly empty /// std::vector DataNodeSelectionToVector(mitk::DataNodeSelection::ConstPointer currentSelection) const; //# protected fields protected: /// /// helper stuff to observe BlueBerry selections /// friend struct berry::SelectionChangedAdapter; /// /// Saves the parent of this view (this is the scrollarea created in CreatePartControl(QWidget*) /// \see CreatePartControl(QWidget*) /// QWidget* m_Parent; /// /// Saves if this view is the currently active one. /// bool m_Active; /// /// Saves if this view is visible /// bool m_Visible; //# private fields: private: /// /// Holds the current selection (selection made by this Functionality !!!) /// QmitkFunctionalitySelectionProvider* m_SelectionProvider; /// /// object to observe BlueBerry selections /// QScopedPointer m_BlueBerrySelectionListener; ctkServiceTracker m_DataStorageServiceTracker; /// /// Saves if this view handles multiple datastorages /// bool m_HandlesMultipleDataStorages; /// /// Saves if this class is currently working on DataStorage changes. /// This is a protector variable to avoid recursive calls on event listener functions. bool m_InDataStorageChanged; /// /// saves all visible functionalities /// std::set m_VisibleFunctionalities; }; #endif /*QMITKFUNCTIONALITY_H_*/ diff --git a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionalityCoordinator.cpp b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionalityCoordinator.cpp index ff628d221b..4da27d3252 100644 --- a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionalityCoordinator.cpp +++ b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionalityCoordinator.cpp @@ -1,220 +1,220 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkFunctionalityCoordinator.h" #include "QmitkFunctionality.h" #include #include #include #include QmitkFunctionalityCoordinator::QmitkFunctionalityCoordinator() : m_StandaloneFuntionality(nullptr) { } void QmitkFunctionalityCoordinator::Start() { berry::PlatformUI::GetWorkbench()->AddWindowListener(this); QList wnds(berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows()); for (auto i = wnds.begin(); i != wnds.end(); ++i) { (*i)->GetPartService()->AddPartListener(this); } } void QmitkFunctionalityCoordinator::Stop() { if (!berry::PlatformUI::IsWorkbenchRunning()) return; berry::PlatformUI::GetWorkbench()->RemoveWindowListener(this); QList wnds(berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows()); for (auto i = wnds.begin(); i != wnds.end(); ++i) { (*i)->GetPartService()->RemovePartListener(this); } } QmitkFunctionalityCoordinator::~QmitkFunctionalityCoordinator() { } berry::IPartListener::Events::Types QmitkFunctionalityCoordinator::GetPartEventTypes() const { return berry::IPartListener::Events::ACTIVATED | berry::IPartListener::Events::DEACTIVATED | berry::IPartListener::Events::CLOSED | berry::IPartListener::Events::HIDDEN | berry::IPartListener::Events::VISIBLE | berry::IPartListener::Events::OPENED; } void QmitkFunctionalityCoordinator::PartActivated( const berry::IWorkbenchPartReference::Pointer& partRef ) { // change the active standalone functionality this->ActivateStandaloneFunctionality(partRef.GetPointer()); } void QmitkFunctionalityCoordinator::PartDeactivated( const berry::IWorkbenchPartReference::Pointer& /*partRef*/ ) { // nothing to do here: see PartActivated() } void QmitkFunctionalityCoordinator::PartOpened( const berry::IWorkbenchPartReference::Pointer& partRef ) { // check for multiwidget and inform views that it is available now if ( partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID ) { for (std::set::iterator it = m_Functionalities.begin() ; it != m_Functionalities.end(); it++) { - (*it)->StdMultiWidgetAvailable(*(partRef - ->GetPart(false).Cast()->GetStdMultiWidget())); + (*it)->MultiWidgetAvailable(*(partRef + ->GetPart(false).Cast()->GetMultiWidget())); } } else { // Check for QmitkFunctionality QmitkFunctionality::Pointer _QmitkFunctionality = partRef->GetPart(false).Cast(); if(_QmitkFunctionality.IsNotNull()) { m_Functionalities.insert(_QmitkFunctionality.GetPointer()); // save as opened functionality } } } void QmitkFunctionalityCoordinator::PartClosed( const berry::IWorkbenchPartReference::Pointer& partRef ) { // check for multiwidget and inform views that it not available any more if ( partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID ) { QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); for (std::set::iterator it = m_Functionalities.begin() ; it != m_Functionalities.end(); it++) { - (*it)->StdMultiWidgetClosed(*(stdMultiWidgetEditor->GetStdMultiWidget())); - (*it)->StdMultiWidgetNotAvailable(); // deprecated call, provided for consistence + (*it)->MultiWidgetClosed(*(stdMultiWidgetEditor->GetMultiWidget())); + (*it)->MultiWidgetNotAvailable(); // deprecated call, provided for consistence } } else { // check for functionality QmitkFunctionality::Pointer _QmitkFunctionality = partRef->GetPart(false).Cast(); if(_QmitkFunctionality.IsNotNull()) { // deactivate on close ( the standalone functionality may still be activated ) this->DeactivateStandaloneFunctionality(partRef.GetPointer(), nullptr); // and set pointer to 0 if(m_StandaloneFuntionality == partRef.GetPointer()) m_StandaloneFuntionality = nullptr; m_Functionalities.erase(_QmitkFunctionality.GetPointer()); // remove as opened functionality // call PartClosed on the QmitkFunctionality _QmitkFunctionality->ClosePartProxy(); //m_VisibleStandaloneFunctionalities.erase(_QmitkFunctionality.GetPointer()); // remove if necessary (should be done before in PartHidden() } } } void QmitkFunctionalityCoordinator::PartHidden( const berry::IWorkbenchPartReference::Pointer& partRef ) { // Check for QmitkFunctionality QmitkFunctionality::Pointer _QmitkFunctionality = partRef->GetPart(false).Cast(); if(_QmitkFunctionality != 0) { _QmitkFunctionality->SetVisible(false); _QmitkFunctionality->Hidden(); // tracking of Visible Standalone Functionalities m_VisibleStandaloneFunctionalities.erase(partRef.GetPointer()); // activate Functionality if just one Standalone Functionality is visible if( m_VisibleStandaloneFunctionalities.size() == 1 ) this->ActivateStandaloneFunctionality( *m_VisibleStandaloneFunctionalities.begin() ); } } void QmitkFunctionalityCoordinator::PartVisible( const berry::IWorkbenchPartReference::Pointer& partRef ) { // Check for QmitkFunctionality QmitkFunctionality::Pointer _QmitkFunctionality = partRef->GetPart(false).Cast(); if(_QmitkFunctionality.IsNotNull()) { _QmitkFunctionality->SetVisible(true); _QmitkFunctionality->Visible(); // tracking of Visible Standalone Functionalities if( _QmitkFunctionality->IsExclusiveFunctionality() ) { m_VisibleStandaloneFunctionalities.insert(partRef.GetPointer()); // activate Functionality if just one Standalone Functionality is visible if( m_VisibleStandaloneFunctionalities.size() == 1 ) this->ActivateStandaloneFunctionality( *m_VisibleStandaloneFunctionalities.begin() ); } } } void QmitkFunctionalityCoordinator::ActivateStandaloneFunctionality( berry::IWorkbenchPartReference* partRef ) { QmitkFunctionality* functionality = dynamic_cast(partRef->GetPart(false).GetPointer()); if( functionality && !functionality->IsActivated() && functionality->IsExclusiveFunctionality() ) { MITK_INFO << "**** Activating legacy standalone functionality"; // deactivate old one if necessary this->DeactivateStandaloneFunctionality(m_StandaloneFuntionality, partRef); m_StandaloneFuntionality = partRef; MITK_INFO << "setting active flag"; // call activated on this functionality functionality->SetActivated(true); functionality->Activated(); } else if (dynamic_cast(partRef->GetPart(false).GetPointer()) && m_StandaloneFuntionality != partRef) { this->DeactivateStandaloneFunctionality(m_StandaloneFuntionality, partRef); m_StandaloneFuntionality = partRef; } } void QmitkFunctionalityCoordinator::DeactivateStandaloneFunctionality(berry::IWorkbenchPartReference* partRef, berry::IWorkbenchPartReference* newRef) { if (partRef == nullptr) return; QmitkFunctionality* functionality = dynamic_cast(partRef->GetPart(false).GetPointer()); if(functionality && functionality->IsActivated()) { functionality->SetActivated(false); functionality->Deactivated(); } else if (mitk::IZombieViewPart* zombie = dynamic_cast(partRef->GetPart(false).GetPointer())) { zombie->ActivatedZombieView(berry::IWorkbenchPartReference::Pointer(newRef)); } } void QmitkFunctionalityCoordinator::WindowClosed(const berry::IWorkbenchWindow::Pointer& /*window*/ ) { } void QmitkFunctionalityCoordinator::WindowOpened(const berry::IWorkbenchWindow::Pointer& window ) { window->GetPartService()->AddPartListener(this); } diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index c3b68caa5d..67e72c7578 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,69 +1,72 @@ set(SRC_CPP_FILES + QmitkAbstractMultiWidgetEditor.cpp QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp QmitkSelectionServiceConnector.cpp QmitkSliceNavigationListener.cpp QmitkSingleNodeSelectionWidget.cpp QmitkNodeSelectionDialog.cpp QmitkAbstractNodeSelectionWidget.cpp QmitkMultiNodeSelectionWidget.cpp + QmitkMultiWidgetDecorationManager.cpp QmitkNodeSelectionPreferenceHelper.cpp QmitkNodeSelectionButton.cpp QmitkSimpleTextOverlayWidget.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp QmitkNodeSelectionConstants.cpp QmitkNodeSelectionPreferencePage.cpp QmitkNodeSelectionListItemWidget.cpp ) set(UI_FILES src/QmitkSingleNodeSelectionWidget.ui src/QmitkMultiNodeSelectionWidget.ui src/QmitkNodeSelectionDialog.ui src/internal/QmitkNodeSelectionPreferencePage.ui src/internal/QmitkNodeSelectionListItemWidget.ui ) set(MOC_H_FILES + src/QmitkAbstractMultiWidgetEditor.h src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h src/QmitkSelectionServiceConnector.h src/QmitkSliceNavigationListener.h src/ImporterUtil.h src/QmitkSingleNodeSelectionWidget.h src/QmitkNodeSelectionDialog.h src/QmitkAbstractNodeSelectionWidget.h src/QmitkMultiNodeSelectionWidget.h src/QmitkNodeSelectionButton.h src/QmitkSimpleTextOverlayWidget.h src/internal/QmitkCommonActivator.h src/internal/QmitkNodeSelectionPreferencePage.h src/internal/QmitkNodeSelectionListItemWidget.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/times.svg ) set(QRC_FILES resources/common.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp new file mode 100644 index 0000000000..f5d57b8c9a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.cpp @@ -0,0 +1,252 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkAbstractMultiWidgetEditor.h" + +// mitk qt widgets module +#include +#include + +// mitk gui qt common plugin +#include "QmitkMultiWidgetDecorationManager.h" + +// berry +#include + +const QString QmitkAbstractMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.abstractmultiwidget"; + +struct QmitkAbstractMultiWidgetEditor::Impl final +{ + Impl(); + ~Impl() = default; + + QmitkAbstractMultiWidget* m_MultiWidget; + + std::unique_ptr m_MultiWidgetDecorationManager; +}; + +QmitkAbstractMultiWidgetEditor::Impl::Impl() + : m_MultiWidget(nullptr) +{ + // nothing here +} + +QmitkAbstractMultiWidgetEditor::QmitkAbstractMultiWidgetEditor() + : m_Impl(std::make_unique()) +{ + // nothing here +} + +QmitkAbstractMultiWidgetEditor::~QmitkAbstractMultiWidgetEditor() {} + +QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetActiveQmitkRenderWindow() const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + auto activeRenderWindowWidget = multiWidget->GetActiveRenderWindowWidget(); + if (nullptr != activeRenderWindowWidget) + { + return activeRenderWindowWidget->GetRenderWindow(); + } + } + + return nullptr; +} + +QHash QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindows() const +{ + QHash result; + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return result; + } + + result = multiWidget->GetRenderWindows(); + return result; +} + +QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindow(const QString& id) const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return nullptr; + } + + return multiWidget->GetRenderWindow(id); +} + +QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return nullptr; + } + + return multiWidget->GetRenderWindow(viewDirection); +} + +mitk::Point3D QmitkAbstractMultiWidgetEditor::GetSelectedPosition(const QString& id/* = QString()*/) const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return mitk::Point3D(); + } + + return multiWidget->GetSelectedPosition(id); +} + +void QmitkAbstractMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D& pos, const QString& id/* = QString()*/) +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + return multiWidget->SetSelectedPosition(pos, id); + } +} + +void QmitkAbstractMultiWidgetEditor::EnableDecorations(bool enable, const QStringList& decorations) +{ + m_Impl->m_MultiWidgetDecorationManager->ShowDecorations(enable, decorations); +} + +bool QmitkAbstractMultiWidgetEditor::IsDecorationEnabled(const QString& decoration) const +{ + return m_Impl->m_MultiWidgetDecorationManager->IsDecorationVisible(decoration); +} + +QStringList QmitkAbstractMultiWidgetEditor::GetDecorations() const +{ + return m_Impl->m_MultiWidgetDecorationManager->GetDecorations(); +} + +berry::IPartListener::Events::Types QmitkAbstractMultiWidgetEditor::GetPartEventTypes() const +{ + return Events::CLOSED | Events::OPENED; +} + +void QmitkAbstractMultiWidgetEditor::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) +{ + if (partRef->GetId() == QmitkAbstractMultiWidgetEditor::EDITOR_ID) + { + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + multiWidget->MultiWidgetOpened(); + } + } +} + +void QmitkAbstractMultiWidgetEditor::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) +{ + if (partRef->GetId() == QmitkAbstractMultiWidgetEditor::EDITOR_ID) + { + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + multiWidget->MultiWidgetClosed(); + } + } +} + +QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindowByIndex(int index) const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return nullptr; + } + + QString renderWindowName = multiWidget->GetNameFromIndex(index); + return multiWidget->GetRenderWindow(renderWindowName); +} + +QmitkRenderWindow* QmitkAbstractMultiWidgetEditor::GetQmitkRenderWindowByIndex(int row, int column) const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return nullptr; + } + + QString renderWindowName = multiWidget->GetNameFromIndex(row, column); + return multiWidget->GetRenderWindow(renderWindowName); +} + +void QmitkAbstractMultiWidgetEditor::SetMultiWidget(QmitkAbstractMultiWidget* multiWidget) +{ + m_Impl->m_MultiWidget = multiWidget; + m_Impl->m_MultiWidgetDecorationManager.reset(new QmitkMultiWidgetDecorationManager(multiWidget)); +} + +QmitkAbstractMultiWidget* QmitkAbstractMultiWidgetEditor::GetMultiWidget() const +{ + return m_Impl->m_MultiWidget; +} + +int QmitkAbstractMultiWidgetEditor::GetRowCount() const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return 0; + } + + return multiWidget->GetRowCount(); +} + +int QmitkAbstractMultiWidgetEditor::GetColumnCount() const +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return 0; + } + + return multiWidget->GetColumnCount(); +} + +void QmitkAbstractMultiWidgetEditor::OnLayoutSet(int row, int column) +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + multiWidget->SetLayout(row, column); + FirePropertyChange(berry::IWorkbenchPartConstants::PROP_INPUT); + } +} + + void QmitkAbstractMultiWidgetEditor::OnSynchronize(bool synchronized) + { + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + multiWidget->Synchronize(synchronized); + } + } + + void QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) + { + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + multiWidget->SetInteractionScheme(scheme); + } + } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h new file mode 100644 index 0000000000..f90972722e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractMultiWidgetEditor.h @@ -0,0 +1,143 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKABSTRACTMULTIWIDGETEDITOR_H +#define QMITKABSTRACTMULTIWIDGETEDITOR_H + +#include + +// org mitk gui qt common plugin +#include + +// mitk core +#include + +// berry +#include + +// c++ +#include + +class QmitkAbstractMultiWidget; +class QmitkLevelWindowWidget; + +class MITK_QT_COMMON QmitkAbstractMultiWidgetEditor : public QmitkAbstractRenderEditor, public berry::IPartListener +{ + Q_OBJECT + +public: + + berryObjectMacro(QmitkAbstractMultiWidgetEditor, QmitkAbstractRenderEditor, IPartListener) + + static const QString EDITOR_ID; + + QmitkAbstractMultiWidgetEditor(); + virtual ~QmitkAbstractMultiWidgetEditor() override; + + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QHash GetQmitkRenderWindows() const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QmitkRenderWindow* GetQmitkRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual bool IsDecorationEnabled(const QString& decoration) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QStringList GetDecorations() const override; + /** + * @brief Overridden from berry::IPartListener + */ + virtual berry::IPartListener::Events::Types GetPartEventTypes() const override; + /** + * @brief Overridden from berry::IPartListener + */ + virtual void PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) override; + /** + * @brief Overridden from berry::IPartListener + */ + virtual void PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) override; + /** + * @brief Retrieve a QmitkRenderWindow by its index. + */ + virtual QmitkRenderWindow* GetQmitkRenderWindowByIndex(int index) const; + /** + * @brief Retrieve a QmitkRenderWindow by the row and column position. + */ + virtual QmitkRenderWindow* GetQmitkRenderWindowByIndex(int row, int column) const; + /** + * @brief Set the current multi widget of this editor. + */ + virtual void SetMultiWidget(QmitkAbstractMultiWidget* multiWidget); + /** + * @brief Return the current multi widget of this editor. + */ + virtual QmitkAbstractMultiWidget* GetMultiWidget() const; + /** + * @brief Return the number of rows of the underlying multi widget. + */ + virtual int GetRowCount() const; + /** + * @brief Return the number of columns of the underlying multi widget. + */ + virtual int GetColumnCount() const; + + virtual QmitkLevelWindowWidget* GetLevelWindowWidget() const = 0; + +public Q_SLOTS: + /** + * @brief A slot that can be called if the layout has been changed. + * This function will call the function 'SetLayout' of the multi widget where + * custom behavior can be implemented. + * Finally 'FirePropertyChange' is called to inform the workbench about an input change. + */ + virtual void OnLayoutSet(int row, int column); + virtual void OnSynchronize(bool synchronized); + virtual void OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); + +private: + + struct Impl; + std::unique_ptr m_Impl; + +}; + +#endif // QMITKABSTRACTMULTIWIDGETEDITOR_H diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiWidgetDecorationManager.cpp similarity index 85% rename from Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp rename to Plugins/org.mitk.gui.qt.common/src/QmitkMultiWidgetDecorationManager.cpp index 6fe8154201..991254cf53 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiWidgetDecorationManager.cpp @@ -1,456 +1,467 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMultiWidgetDecorationManager.h" -// org_mitk_gui_common +// org mitk gui common plugin #include -// mitk annotation +// mitk annotation module #include +// mitk qt widgets module +#include + // vtk #include // qt #include -QmitkMultiWidgetDecorationManager::QmitkMultiWidgetDecorationManager(QmitkMxNMultiWidget* mxnMultiWidget) - : m_MxNMultiWidget(mxnMultiWidget) +QmitkMultiWidgetDecorationManager::QmitkMultiWidgetDecorationManager(QmitkAbstractMultiWidget* multiWidget) + : m_MultiWidget(multiWidget) , m_LogoAnnotation(mitk::LogoAnnotation::New()) -{} +{ + // nothing here +} void QmitkMultiWidgetDecorationManager::DecorationPreferencesChanged(const berry::IBerryPreferences* preferences) { - // Enable change of logo. If no DepartmentLogo was set explicitly, MITK Logo is used. + // Enable change of logo. If no DepartmentLogo was set explicitly, MBILogo is used. // Set new department logo by prefs->Set("DepartmentLogo", "PathToImage"); // If no logo was set for this plug-in specifically, walk the parent preference nodes // and lookup a logo value there. // Disable the logo first, otherwise setting a new logo will have no effect due to how mitkManufacturerLogo works ShowLogo(false); - SetupLogo(qPrintable(":/org.mitk.gui.qt.mxnmultiwidgeteditor/defaultWatermark.png")); + SetupLogo(qPrintable(":/org.mitk.gui.qt.stdmultiwidgeteditor/defaultWatermark.png")); ShowLogo(true); const berry::IPreferences* currentNode = preferences; while (currentNode) { bool logoFound = false; foreach(const QString& key, currentNode->Keys()) { if (key == "DepartmentLogo") { ShowLogo(false); QString departmentLogoLocation = currentNode->Get("DepartmentLogo", ""); if (!departmentLogoLocation.isEmpty()) { SetupLogo(qPrintable(departmentLogoLocation)); ShowLogo(true); } logoFound = true; break; } } if (logoFound) { break; } currentNode = currentNode->Parent().GetPointer(); } + /* QmitkMultiWidgetDecorationManager::Colormap colormap = static_cast(preferences->GetInt("Render window widget colormap", 0)); SetColormap(colormap); + */ // show colored rectangle ShowAllColoredRectangles(true); + // show all gradient background + ShowAllGradientBackgrounds(true); + // show corner annotations ShowAllCornerAnnotations(true); } void QmitkMultiWidgetDecorationManager::ShowDecorations(bool show, const QStringList& decorations) { - if (nullptr != m_MxNMultiWidget) + if (nullptr != m_MultiWidget) { return; } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_BORDER)) { ShowAllColoredRectangles(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_LOGO)) { ShowLogo(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_MENU)) { - //m_MxNMultiWidget->ActivateAllRenderWindowMenus(show); + //m_MultiWidget->ActivateAllRenderWindowMenus(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_BACKGROUND)) { ShowAllGradientBackgrounds(show); } if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION)) { ShowAllCornerAnnotations(show); } } bool QmitkMultiWidgetDecorationManager::IsDecorationVisible(const QString& decoration) const { if (mitk::IRenderWindowPart::DECORATION_BORDER == decoration) { return AreAllColoredRectanglesVisible(); } else if (mitk::IRenderWindowPart::DECORATION_LOGO == decoration) { return IsLogoVisible(); } else if (mitk::IRenderWindowPart::DECORATION_MENU == decoration) { //return IsMenuWidgetEnabled(); } else if (mitk::IRenderWindowPart::DECORATION_BACKGROUND == decoration) { return AreAllGradientBackgroundsOn(); } else if (mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION == decoration) { return AreAllCornerAnnotationsVisible(); } return false; } QStringList QmitkMultiWidgetDecorationManager::GetDecorations() const { QStringList decorations; decorations << mitk::IRenderWindowPart::DECORATION_BORDER << mitk::IRenderWindowPart::DECORATION_LOGO << mitk::IRenderWindowPart::DECORATION_MENU << mitk::IRenderWindowPart::DECORATION_BACKGROUND << mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION; return decorations; } -////////////////////////////////////////////////////////////////////////// -// PRIVATE -////////////////////////////////////////////////////////////////////////// + void QmitkMultiWidgetDecorationManager::SetupLogo(const char* path) { m_LogoAnnotation->SetOpacity(0.5); mitk::Point2D offset; offset.Fill(0.03); m_LogoAnnotation->SetOffsetVector(offset); m_LogoAnnotation->SetRelativeSize(0.25); m_LogoAnnotation->SetCornerPosition(1); vtkSmartPointer vtkLogo = GetVtkLogo(path); SetLogo(vtkLogo); } -vtkSmartPointer QmitkMultiWidgetDecorationManager::GetVtkLogo(const char* path) -{ - QImage* qimage = new QImage(path); - vtkSmartPointer qImageToVtk; - qImageToVtk = vtkSmartPointer::New(); - - qImageToVtk->SetQImage(qimage); - qImageToVtk->Update(); - vtkSmartPointer vtkLogo = qImageToVtk->GetOutput(); - return vtkLogo; -} - -void QmitkMultiWidgetDecorationManager::SetLogo(vtkSmartPointer vtkLogo) -{ - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetLastRenderWindowWidget(); - if (nullptr != renderWindowWidget && m_LogoAnnotation.IsNotNull()) - { - mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_LogoAnnotation.GetPointer(), renderWindowWidget->GetRenderWindow()->GetRenderer()); - m_LogoAnnotation->SetLogoImage(vtkLogo); - mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(renderWindowWidget->GetRenderWindow()->GetVtkRenderWindow()); - m_LogoAnnotation->Update(renderer); - renderWindowWidget->RequestUpdate(); - return; - } - - MITK_ERROR << "Logo can not be set for an unknown widget."; -} - void QmitkMultiWidgetDecorationManager::ShowLogo(bool show) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetLastRenderWindowWidget(); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetLastRenderWindowWidget(); if (nullptr != renderWindowWidget) { m_LogoAnnotation->SetVisibility(show); renderWindowWidget->RequestUpdate(); return; } MITK_ERROR << "Logo can not be shown for an unknown widget."; } bool QmitkMultiWidgetDecorationManager::IsLogoVisible() const { return m_LogoAnnotation->IsVisible(); } void QmitkMultiWidgetDecorationManager::SetColormap(QmitkMultiWidgetDecorationManager::Colormap colormap) { switch (colormap) { - case Colormap::BlackAndWhite: - { - FillAllGradientBackgroundColorsWithBlack(); - float white[3] = { 1.0f, 1.0f, 1.0f }; - SetAllDecorationColors(white); - break; - } + case Colormap::BlackAndWhite: + { + FillAllGradientBackgroundColorsWithBlack(); + float white[3] = { 1.0f, 1.0f, 1.0f }; + SetAllDecorationColors(white); + break; + } } } void QmitkMultiWidgetDecorationManager::SetDecorationColor(const QString& widgetID, const mitk::Color& color) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetDecorationColor(color); return; } MITK_ERROR << "Decoration color can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::SetAllDecorationColors(const mitk::Color& color) { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->SetDecorationColor(color); } } mitk::Color QmitkMultiWidgetDecorationManager::GetDecorationColor(const QString& widgetID) const { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetDecorationColor(); } MITK_ERROR << "Decoration color can not be retrieved for an unknown widget. Returning black color!"; float black[3] = { 0.0f, 0.0f, 0.0f }; return mitk::Color(black); } void QmitkMultiWidgetDecorationManager::ShowColoredRectangle(const QString& widgetID, bool show) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowColoredRectangle(show); return; } MITK_ERROR << "Colored rectangle can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowAllColoredRectangles(bool show) { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ShowColoredRectangle(show); } } bool QmitkMultiWidgetDecorationManager::IsColoredRectangleVisible(const QString& widgetID) const { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->IsColoredRectangleVisible(); } MITK_ERROR << "Colored rectangle visibility can not be retrieved for an unknown widget. Returning 'false'."; return false; } bool QmitkMultiWidgetDecorationManager::AreAllColoredRectanglesVisible() const { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); bool allTrue = true; for (const auto& renderWindowWidget : renderWindowWidgets) { allTrue = allTrue && renderWindowWidget.second->IsColoredRectangleVisible(); } return allTrue; } void QmitkMultiWidgetDecorationManager::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower, const QString& widgetID) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetGradientBackgroundColors(upper, lower); return; } MITK_ERROR << "Background color gradient can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::SetAllGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->SetGradientBackgroundColors(upper, lower); } } void QmitkMultiWidgetDecorationManager::FillAllGradientBackgroundColorsWithBlack() { float black[3] = { 0.0f, 0.0f, 0.0f }; SetAllGradientBackgroundColors(black, black); } void QmitkMultiWidgetDecorationManager::ShowGradientBackground(const QString& widgetID, bool show) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowGradientBackground(show); return; } MITK_ERROR << "Background color gradient can not be shown for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowAllGradientBackgrounds(bool show) { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ShowGradientBackground(show); } } std::pair QmitkMultiWidgetDecorationManager::GetGradientBackgroundColors(const QString& widgetID) const { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetGradientBackgroundColors(); } MITK_ERROR << "Background color gradient can not be retrieved for an unknown widget. Returning black color pair."; float black[3] = { 0.0f, 0.0f, 0.0f }; return std::make_pair(mitk::Color(black), mitk::Color(black)); } bool QmitkMultiWidgetDecorationManager::IsGradientBackgroundOn(const QString& widgetID) const { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->IsGradientBackgroundOn(); } MITK_ERROR << "Background color gradient flag can not be retrieved for an unknown widget. Returning 'false'."; return false; } bool QmitkMultiWidgetDecorationManager::AreAllGradientBackgroundsOn() const { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); bool allTrue = true; for (const auto& renderWindowWidget : renderWindowWidgets) { allTrue = allTrue && renderWindowWidget.second->IsGradientBackgroundOn(); } return allTrue; } void QmitkMultiWidgetDecorationManager::SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); return; } MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; } std::string QmitkMultiWidgetDecorationManager::GetCornerAnnotationText(const QString& widgetID) const { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetCornerAnnotationText(); } MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; return ""; } void QmitkMultiWidgetDecorationManager::ShowCornerAnnotation(const QString& widgetID, bool show) { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowCornerAnnotation(show); return; } MITK_ERROR << "Corner annotation can not be set for an unknown widget."; } void QmitkMultiWidgetDecorationManager::ShowAllCornerAnnotations(bool show) { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ShowCornerAnnotation(show); } } bool QmitkMultiWidgetDecorationManager::IsCornerAnnotationVisible(const QString& widgetID) const { - std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + std::shared_ptr renderWindowWidget = m_MultiWidget->GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->IsCornerAnnotationVisible(); } MITK_ERROR << "Corner annotation visibility can not be retrieved for an unknown widget. Returning 'false'."; return false; } bool QmitkMultiWidgetDecorationManager::AreAllCornerAnnotationsVisible() const { - QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MultiWidget->GetRenderWindowWidgets(); bool allTrue = true; for (const auto& renderWindowWidget : renderWindowWidgets) { allTrue = allTrue && renderWindowWidget.second->IsCornerAnnotationVisible(); } return allTrue; } + +////////////////////////////////////////////////////////////////////////// +// PRIVATE +////////////////////////////////////////////////////////////////////////// +vtkSmartPointer QmitkMultiWidgetDecorationManager::GetVtkLogo(const char* path) +{ + QImage* qimage = new QImage(path); + vtkSmartPointer qImageToVtk; + qImageToVtk = vtkSmartPointer::New(); + + qImageToVtk->SetQImage(qimage); + qImageToVtk->Update(); + vtkSmartPointer vtkLogo = qImageToVtk->GetOutput(); + return vtkLogo; +} + +void QmitkMultiWidgetDecorationManager::SetLogo(vtkSmartPointer vtkLogo) +{ + std::shared_ptr renderWindowWidget = m_MultiWidget->GetLastRenderWindowWidget(); + if (nullptr != renderWindowWidget && m_LogoAnnotation.IsNotNull()) + { + mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_LogoAnnotation.GetPointer(), renderWindowWidget->GetRenderWindow()->GetRenderer()); + m_LogoAnnotation->SetLogoImage(vtkLogo); + mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(renderWindowWidget->GetRenderWindow()->GetVtkRenderWindow()); + m_LogoAnnotation->Update(renderer); + renderWindowWidget->RequestUpdate(); + return; + } + + MITK_ERROR << "Logo can not be set for an unknown widget."; +} diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.h b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiWidgetDecorationManager.h similarity index 88% rename from Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.h rename to Plugins/org.mitk.gui.qt.common/src/QmitkMultiWidgetDecorationManager.h index 8cc45cf9fa..c0f60c5d54 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiWidgetDecorationManager.h @@ -1,144 +1,144 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKMXNMULTIWIDGETDECORATIONMANAGER_H -#define QMITKMXNMULTIWIDGETDECORATIONMANAGER_H +#ifndef QMITKMULTIWIDGETDECORATIONMANAGER_H +#define QMITKMULTIWIDGETDECORATIONMANAGER_H -// mxn multi widget editor -#include +#include // mitk core #include // mitk annotation #include -// mitk qtwidgets -#include +// mitk qt widgets +#include // berry #include // vtk #include #include // qt #include #include /** * @brief * * */ -class MXNMULTIWIDGETEDITOR_EXPORT QmitkMultiWidgetDecorationManager +class MITK_QT_COMMON QmitkMultiWidgetDecorationManager { public: - QmitkMultiWidgetDecorationManager(QmitkMxNMultiWidget* mxnMultiWidget); + QmitkMultiWidgetDecorationManager(QmitkAbstractMultiWidget* multiWidget); enum class Colormap { BlackAndWhite = 0 // black background, white decoration }; void DecorationPreferencesChanged(const berry::IBerryPreferences* preferences); /** * @brief Show or hide decorations like like colored borders or background, logos, menu widgets, logos and * text annotations. * * \@par Show the decorations specified in decorations if true. Hide them, if not. * \@par A list of decoration names. If empty, all supported decorations are affected. */ void ShowDecorations(bool show, const QStringList& decorations); /** * @brief Return if a specific decoration is visible. * * \return True, if the specified decoration is shown, false if not. */ bool IsDecorationVisible(const QString &decoration) const; QStringList GetDecorations() const; -private: - void SetupLogo(const char* path); - vtkSmartPointer GetVtkLogo(const char* path); - void SetLogo(vtkSmartPointer vtkLogo); void ShowLogo(bool show); bool IsLogoVisible() const; void SetColormap(Colormap colormap); void SetDecorationColor(const QString& widgetID, const mitk::Color& color); void SetAllDecorationColors(const mitk::Color& color); mitk::Color GetDecorationColor(const QString& widgetID) const; void ShowColoredRectangle(const QString& widgetID, bool show); void ShowAllColoredRectangles(bool show); bool IsColoredRectangleVisible(const QString& widgetID) const; bool AreAllColoredRectanglesVisible() const; /** * @brief Set a background color gradient for a specific render window. * * If two different input colors are used, a gradient background is generated. * * @param upper The color of the gradient background. * @param lower The color of the gradient background. * @param widgetID The widget identifier. */ void SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower, const QString& widgetID); /** * @brief Set a background color gradient for all available render windows. * * If two different input colors are used, a gradient background is generated. * * @param upper The color of the gradient background. * @param lower The color of the gradient background. */ void SetAllGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower); void FillAllGradientBackgroundColorsWithBlack(); void ShowGradientBackground(const QString& widgetID, bool show); void ShowAllGradientBackgrounds(bool show); /** - * @brief Return a render window (widget) specific background color gradient + * @rief Return a render window (widget) specific background color gradient * * @param widgetID The widget identifier. * * @return A color gradient as a pair of colors. * First entry: upper color value * Second entry: lower color value */ std::pair GetGradientBackgroundColors(const QString& widgetID) const; bool IsGradientBackgroundOn(const QString& widgetID) const; bool AreAllGradientBackgroundsOn() const; void SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation); std::string GetCornerAnnotationText(const QString& widgetID) const; void ShowCornerAnnotation(const QString& widgetID, bool show); void ShowAllCornerAnnotations(bool show); bool IsCornerAnnotationVisible(const QString& widgetID) const; bool AreAllCornerAnnotationsVisible() const; - QmitkMxNMultiWidget* m_MxNMultiWidget; +private: + + vtkSmartPointer GetVtkLogo(const char* path); + void SetLogo(vtkSmartPointer vtkLogo); + + QmitkAbstractMultiWidget* m_MultiWidget; mitk::LogoAnnotation::Pointer m_LogoAnnotation; }; -#endif // QMITKMXNMULTIWIDGETDECORATIONMANAGER_H +#endif // QMITKMULTIWIDGETDECORATIONMANAGER_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp index ccb9b32a49..8633586784 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.cpp @@ -1,1169 +1,1168 @@ /*========================================================================= The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. =========================================================================*/ #include // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingDataEvaluationView.h" -#include "QmitkStdMultiWidget.h" // Qt #include #include #include // MITK #include "mitkNavigationDataCSVSequentialPlayer.h" #include #include #include #include #include //ITK #include //VNL #include //vtk headers #include #include #include const std::string QmitkIGTTrackingDataEvaluationView::VIEW_ID = "org.mitk.views.igttrackingdataevaluation"; QmitkIGTTrackingDataEvaluationView::QmitkIGTTrackingDataEvaluationView() : QmitkFunctionality() , m_Controls(nullptr) , m_MultiWidget(nullptr) , m_scalingfactor(1) { m_CSVtoXMLInputFilenameVector = std::vector(); m_CSVtoXMLOutputFilenameVector = std::vector(); } QmitkIGTTrackingDataEvaluationView::~QmitkIGTTrackingDataEvaluationView() { } void QmitkIGTTrackingDataEvaluationView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIGTTrackingDataEvaluationViewControls; m_Controls->setupUi(parent); connect(m_Controls->m_LoadInputFileList, SIGNAL(clicked()), this, SLOT(OnLoadFileList())); connect(m_Controls->m_StartEvaluation, SIGNAL(clicked()), this, SLOT(OnEvaluateData())); connect(m_Controls->m_AddToCurrentList, SIGNAL(clicked()), this, SLOT(OnAddToCurrentList())); connect(m_Controls->m_GeneratePointSetOfMeanPositions, SIGNAL(clicked()), this, SLOT(OnGeneratePointSet())); connect(m_Controls->m_GenerateRotationLines, SIGNAL(clicked()), this, SLOT(OnGenerateRotationLines())); connect(m_Controls->m_GeneratePointSet, SIGNAL(clicked()), this, SLOT(OnGenerateGroundTruthPointSet())); connect(m_Controls->m_Convert, SIGNAL(clicked()), this, SLOT(OnConvertCSVtoXMLFile())); connect(m_Controls->m_loadCSVtoXMLInputList, SIGNAL(clicked()), this, SLOT(OnCSVtoXMLLoadInputList())); connect(m_Controls->m_loadCSVtoXMLOutputList, SIGNAL(clicked()), this, SLOT(OnCSVtoXMLLoadOutputList())); connect(m_Controls->m_OrientationCalculationGenerateReference, SIGNAL(clicked()), this, SLOT(OnOrientationCalculation_CalcRef())); connect(m_Controls->m_OrientationCalculationWriteOrientationsToFile, SIGNAL(clicked()), this, SLOT(OnOrientationCalculation_CalcOrientandWriteToFile())); connect(m_Controls->m_GeneratePointSetsOfSinglePositions, SIGNAL(clicked()), this, SLOT(OnGeneratePointSetsOfSinglePositions())); connect(m_Controls->m_StartEvaluationAll, SIGNAL(clicked()), this, SLOT(OnEvaluateDataAll())); connect(m_Controls->m_GridMatching, SIGNAL(clicked()), this, SLOT(OnPerfomGridMatching())); connect(m_Controls->m_ComputeRotation, SIGNAL(clicked()), this, SLOT(OnComputeRotation())); //initialize data storage combo boxes m_Controls->m_ReferencePointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ReferencePointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_ReferencePointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); m_Controls->m_MeasurementPointSetComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MeasurementPointSetComboBox->SetAutoSelectNewItems(true); m_Controls->m_MeasurementPointSetComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); } } void QmitkIGTTrackingDataEvaluationView::OnComputeRotation() { //Get all data from UI auto EvaluationDataCollection = GetAllDataFromUIList(); //Compute mean Quaternions auto OrientationVector = GetMeanOrientationsOfAllData(EvaluationDataCollection); //Compute Rotations itk::Vector rotationVec; //adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = m_Controls->m_rotVecX->value(); //X rotationVec[1] = m_Controls->m_rotVecY->value(); //Y rotationVec[2] = m_Controls->m_rotVecZ->value(); //Z std::vector allOrientationErrors; for (std::vector::size_type i = 0; i < OrientationVector.size() - 1; ++i) { double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(OrientationVector.at(i), OrientationVector.at(i+1), rotationVec); double AngularError = fabs(AngleBetweenTwoQuaternions - 11.25); std::stringstream description; description << "Rotation Error ROT" << (i + 1) << " / ROT" << (i + 2); allOrientationErrors.push_back({ AngularError, description.str() }); MITK_INFO << description.str() << ": " << AngularError; } //compute statistics std::vector orientationErrorStatistics; orientationErrorStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(allOrientationErrors); MITK_INFO << "## Rotation error statistics: ##"; for (auto stat : orientationErrorStatistics) { MITK_INFO << stat.description << ": " << stat.distanceError; } //write results to file allOrientationErrors.insert(allOrientationErrors.end(), orientationErrorStatistics.begin(), orientationErrorStatistics.end()); allOrientationErrors.push_back({rotationVec[0],"Rot Vector [x]"}); allOrientationErrors.push_back({rotationVec[1], "Rot Vector [y]"}); allOrientationErrors.push_back({rotationVec[2], "Rot Vector [z]"}); std::stringstream filenameOrientationStat; filenameOrientationStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".orientationStatistics.csv"; MITK_INFO << "Writing output to file " << filenameOrientationStat.str(); writeToFile(filenameOrientationStat.str(), allOrientationErrors); } void QmitkIGTTrackingDataEvaluationView::OnPerfomGridMatching() { mitk::PointSet::Pointer reference = dynamic_cast(m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()); mitk::PointSet::Pointer measurement = dynamic_cast(m_Controls->m_MeasurementPointSetComboBox->GetSelectedNode()->GetData()); //convert point sets to vtk poly data vtkSmartPointer sourcePoints = vtkSmartPointer::New(); vtkSmartPointer targetPoints = vtkSmartPointer::New(); for (int i = 0; iGetSize(); i++) { double point[3] = { reference->GetPoint(i)[0], reference->GetPoint(i)[1], reference->GetPoint(i)[2] }; sourcePoints->InsertNextPoint(point); double point_targets[3] = { measurement->GetPoint(i)[0], measurement->GetPoint(i)[1], measurement->GetPoint(i)[2] }; targetPoints->InsertNextPoint(point_targets); } //compute transform vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->SetModeToRigidBody(); transform->Modified(); transform->Update(); //compute FRE of transform double FRE = mitk::StaticIGTHelperFunctions::ComputeFRE(reference, measurement, transform); MITK_INFO << "FRE after grid matching: " + QString::number(FRE) + " mm"; //convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); itk::Matrix rotationDouble = itk::Matrix(); itk::Vector translationDouble = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); for (int k = 0; k<3; k++) for (int l = 0; l<3; l++) { rotationFloat[k][l] = m->GetElement(k, l); rotationDouble[k][l] = m->GetElement(k, l); } for (int k = 0; k<3; k++) { translationFloat[k] = m->GetElement(k, 3); translationDouble[k] = m->GetElement(k, 3); } //create affine transform 3D mitk::AffineTransform3D::Pointer mitkTransform = mitk::AffineTransform3D::New(); mitkTransform->SetMatrix(rotationDouble); mitkTransform->SetOffset(translationDouble); mitk::NavigationData::Pointer transformNavigationData = mitk::NavigationData::New(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(mitkTransform); m_Controls->m_ReferencePointSetComboBox->GetSelectedNode()->GetData()->GetGeometry()->Modified(); //write to file std::stringstream filename; filename << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".GridMatchingResult.csv"; MITK_INFO << "Writing output to file " << filename.str(); std::vector FRE_Error; FRE_Error.push_back({ FRE, "FRE after grid matching [mm]" }); writeToFile(filename.str(), FRE_Error); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcRef() { if (m_FilenameVector.size() != 3) { MessageBox("Need exactly three points as reference, aborting!"); return; } //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector[i]); //check if the stream is valid and skip file if not //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); //update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); //store mean position as reference switch (i) { case 0: m_RefPoint1 = myEvaluationFilter->GetPositionMean(0); break; case 1: m_RefPoint2 = myEvaluationFilter->GetPositionMean(0); break; case 2: m_RefPoint3 = myEvaluationFilter->GetPositionMean(0); break; } } MessageBox("Created Reference!"); } void QmitkIGTTrackingDataEvaluationView::OnOrientationCalculation_CalcOrientandWriteToFile() { //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //open file header QString outputname = QString(m_FilenameVector.at(i).c_str()) + "_orientationFile.csv"; m_CurrentWriteFile.open(outputname.toStdString().c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } //write header to file m_CurrentWriteFile << "Nr;Calypso_Time;Valid_Reference;MeasureTool_Measurement-Tool[x];MeasureTool_Measurement-Tool[y];MeasureTool_Measurement-Tool[z];MeasureTool_Measurement-Tool[qx];MeasureTool_Measurement-Tool[qy];MeasureTool_Measurement-Tool[qz];MeasureTool_Measurement-Tool[qr]\n"; //update pipeline until number of samples is reached int step = 0; mitk::Point3D point1, point2, point3; mitk::Quaternion current_orientation; for (int j = 0; !myPlayer->IsAtEnd(); j++) { myPlayer->Update(); mitk::NavigationData::Pointer currentNavData = myPlayer->GetOutput(0); switch (step) { case 0: step++; point1 = currentNavData->GetPosition(); break; case 1: step++; point2 = currentNavData->GetPosition(); break; case 2: step = 0; point3 = currentNavData->GetPosition(); //compute transform from reference to current points if (point1[0] == 0 && point1[1] == 0 && point1[2] == 0 && point2[0] == 0 && point2[1] == 0 && point2[2] == 0 && point3[0] == 0 && point3[1] == 0 && point3[2] == 0 ) current_orientation.fill(0); else { vtkSmartPointer transform = vtkSmartPointer::New(); vtkSmartPointer sourcePoints = vtkSmartPointer::New(); double sourcepoint1[3] = { point1[0], point1[1], point1[2] }; double sourcepoint2[3] = { point2[0], point2[1], point2[2] }; double sourcepoint3[3] = { point3[0], point3[1], point3[2] }; sourcePoints->InsertNextPoint(sourcepoint1); sourcePoints->InsertNextPoint(sourcepoint2); sourcePoints->InsertNextPoint(sourcepoint3); vtkSmartPointer targetPoints = vtkSmartPointer::New(); double targetpoint1[3] = { m_RefPoint1[0], m_RefPoint1[1], m_RefPoint1[2] }; double targetpoint2[3] = { m_RefPoint2[0], m_RefPoint2[1], m_RefPoint2[2] }; double targetpoint3[3] = { m_RefPoint3[0], m_RefPoint3[1], m_RefPoint3[2] }; targetPoints->InsertNextPoint(targetpoint1); targetPoints->InsertNextPoint(targetpoint2); targetPoints->InsertNextPoint(targetpoint3); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->Modified(); transform->Update(); mitk::Transform::Pointer newTransform = mitk::Transform::New(); newTransform->SetMatrix(transform->GetMatrix()); current_orientation = newTransform->GetOrientation(); //add pointset with the three positions if ((j > 15) && (j < 18)) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); newPointSet->InsertPoint(0, point1); newPointSet->InsertPoint(1, point2); newPointSet->InsertPoint(2, point3); QString name = QString(m_FilenameVector.at(i).c_str()); newNode->SetName(name.toStdString().c_str()); newNode->SetData(newPointSet); newNode->SetFloatProperty("pointsize", 0.1); this->GetDataStorage()->Add(newNode); } } break; } m_CurrentWriteFile << i << ";"; m_CurrentWriteFile << currentNavData->GetTimeStamp() << ";"; //IMPORTANT: change to GetIGTTimeStamp in new version! m_CurrentWriteFile << "true;"; m_CurrentWriteFile << currentNavData->GetPosition()[0] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[1] << ";"; m_CurrentWriteFile << currentNavData->GetPosition()[2] << ";"; m_CurrentWriteFile << current_orientation.x() << ";"; m_CurrentWriteFile << current_orientation.y() << ";"; m_CurrentWriteFile << current_orientation.z() << ";"; m_CurrentWriteFile << current_orientation.r() << ";"; m_CurrentWriteFile << "\n"; } //close output file m_CurrentWriteFile.close(); } MessageBox("Finished!"); } -void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) +void QmitkIGTTrackingDataEvaluationView::MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) { - m_MultiWidget = &stdMultiWidget; + m_MultiWidget = dynamic_cast(&multiWidget); } -void QmitkIGTTrackingDataEvaluationView::StdMultiWidgetNotAvailable() +void QmitkIGTTrackingDataEvaluationView::MultiWidgetNotAvailable() { m_MultiWidget = nullptr; } void QmitkIGTTrackingDataEvaluationView::OnAddToCurrentList() { //read in files QStringList files = QFileDialog::getOpenFileNames(nullptr, "Select one or more files to open", "/", "CSV (*.csv)"); if (files.isEmpty()) return; for (int i = 0; i < files.size(); i++) { std::string tmp = files.at(i).toStdString().c_str(); m_FilenameVector.push_back(tmp); } //fill list at GUI m_Controls->m_FileList->clear(); for (unsigned int i = 0; i < m_FilenameVector.size(); i++) { new QListWidgetItem(tr(m_FilenameVector.at(i).c_str()), m_Controls->m_FileList); } } void QmitkIGTTrackingDataEvaluationView::OnLoadFileList() { m_FilenameVector = std::vector(); m_FilenameVector.clear(); OnAddToCurrentList(); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateDataAll() { std::vector results5cm, results15cm, results30cm, resultsAccum; mitk::HummelProtocolEvaluation::HummelProtocolMeasurementVolume volume; if (m_Controls->m_standardVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::standard; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); mitk::HummelProtocolEvaluation::Evaluate15cmDistances(m_PointSetMeanPositions, volume, results15cm); mitk::HummelProtocolEvaluation::Evaluate30cmDistances(m_PointSetMeanPositions, volume, results30cm); mitk::HummelProtocolEvaluation::EvaluateAccumulatedDistances(m_PointSetMeanPositions, volume, resultsAccum); } else if (m_Controls->m_smallVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::small; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } else if (m_Controls->m_mediumVolume->isChecked()) { volume = mitk::HummelProtocolEvaluation::medium; mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_PointSetMeanPositions, volume, results5cm); } //write results to file std::stringstream filename5cm; filename5cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results5cm.csv"; MITK_INFO << "Writing output to file " << filename5cm.str(); writeToFile(filename5cm.str(), results5cm); std::stringstream filename15cm; filename15cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results15cm.csv"; MITK_INFO << "Writing output to file " << filename15cm.str(); writeToFile(filename15cm.str(), results15cm); std::stringstream filename30cm; filename30cm << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".results30cm.csv"; MITK_INFO << "Writing output to file " << filename30cm.str(); writeToFile(filename30cm.str(), results30cm); std::stringstream filenameAccum; filenameAccum << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsAccumDist.csv"; MITK_INFO << "Writing output to file " << filenameAccum.str(); writeToFile(filenameAccum.str(), resultsAccum); } void QmitkIGTTrackingDataEvaluationView::OnEvaluateData() { //open output file m_CurrentWriteFile.open(std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str(), std::ios::out); if (m_CurrentWriteFile.bad()) { MessageBox("Error: Can't open output file!"); return; } std::vector jitterValues; //write output file header WriteHeader(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++i) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } if (myPlayer->GetNumberOfSnapshots() < m_Controls->m_NumberOfSamples->value()) { MITK_WARN << "Number of snapshots (" << myPlayer->GetNumberOfSnapshots() << ") smaller than number of samples to evaluate (" << m_Controls->m_NumberOfSamples->value() << ") ! Cannot proceed!"; return; } //update pipline until number of samples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) myEvaluationFilter->Update(); //store all jitter values in separate vector for statistics jitterValues.push_back({ myEvaluationFilter->GetPositionErrorRMS(0), "RMS" }); //write result to output file WriteDataSet(myEvaluationFilter, m_FilenameVector.at(i)); } //close output file for single data m_CurrentWriteFile.close(); //compute statistics std::vector jitterStatistics = mitk::HummelProtocolEvaluation::ComputeStatistics(jitterValues); MITK_INFO << "## Jitter (RMS) statistics: ##"; for (auto jitterStat : jitterStatistics) {MITK_INFO << jitterStat.description << ": " << jitterStat.distanceError;} //write statistic results to separate file std::stringstream filenameJitterStat; filenameJitterStat << std::string(m_Controls->m_OutputFilename->text().toUtf8()).c_str() << ".resultsJitterStatistics.csv"; MITK_INFO << "Writing output to file " << filenameJitterStat.str(); writeToFile(filenameJitterStat.str(), jitterStatistics); //calculate angles if option is on if (m_Controls->m_settingDifferenceAngles->isChecked() || m_Controls->m_DifferencesSLERP->isChecked()) CalculateDifferenceAngles(); MessageBox("Finished!"); } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSetsOfSinglePositions() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create point set for this file mitk::PointSet::Pointer thisPointSet = mitk::PointSet::New(); //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //update pipline until number of samlples is reached and store every single point for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); j++) { myPlayer->Update(); mitk::Point3D thisPoint = myPlayer->GetOutput()->GetPosition(); thisPoint[0] *= m_scalingfactor; thisPoint[1] *= m_scalingfactor; thisPoint[2] *= m_scalingfactor; thisPointSet->InsertPoint(j, thisPoint); } //add point set to data storage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + QString("PointSet_of_All_Positions_") + QString::number(i); newNode->SetName(name.toStdString()); newNode->SetData(thisPointSet); this->GetDataStorage()->Add(newNode); } } void QmitkIGTTrackingDataEvaluationView::OnGeneratePointSet() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) { myEvaluationFilter->Update(); } //add mean position to point set mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } generatedPointSet->InsertPoint(i, meanPos); } //add point set to data storage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name = this->m_Controls->m_prefix->text() + "PointSet_of_Mean_Positions"; newNode->SetName(name.toStdString()); newNode->SetData(generatedPointSet); newNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(newNode); m_PointSetMeanPositions = generatedPointSet; } void QmitkIGTTrackingDataEvaluationView::OnGenerateRotationLines() { m_scalingfactor = m_Controls->m_ScalingFactor->value(); //start loop and iterate through all files of list for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) { myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); } //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); //create line from mean pos to a second point which lies along the sensor (1,0,0 in tool coordinates for aurora) mitk::Point3D meanPos = myEvaluationFilter->GetPositionMean(0); if (m_scalingfactor != 1) { meanPos[0] *= m_scalingfactor; meanPos[1] *= m_scalingfactor; meanPos[2] *= m_scalingfactor; } mitk::Point3D secondPoint; mitk::Point3D thirdPoint; mitk::Point3D fourthPoint; mitk::FillVector3D(secondPoint, 2, 0, 0); //X vnl_vector secondPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * secondPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D secondPointTransformedMITK; mitk::FillVector3D(secondPointTransformedMITK, secondPointTransformed[0], secondPointTransformed[1], secondPointTransformed[2]); mitk::FillVector3D(thirdPoint, 0, 4, 0); //Y vnl_vector thirdPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * thirdPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D thirdPointTransformedMITK; mitk::FillVector3D(thirdPointTransformedMITK, thirdPointTransformed[0], thirdPointTransformed[1], thirdPointTransformed[2]); mitk::FillVector3D(fourthPoint, 0, 0, 6); //Z vnl_vector fourthPointTransformed = myEvaluationFilter->GetQuaternionMean(0).rotation_matrix_transpose().transpose() * fourthPoint.GetVnlVector() + meanPos.GetVnlVector(); mitk::Point3D fourthPointTransformedMITK; mitk::FillVector3D(fourthPointTransformedMITK, fourthPointTransformed[0], fourthPointTransformed[1], fourthPointTransformed[2]); mitk::PointSet::Pointer rotationLine = mitk::PointSet::New(); rotationLine->InsertPoint(0, secondPointTransformedMITK); rotationLine->InsertPoint(1, meanPos); rotationLine->InsertPoint(2, thirdPointTransformedMITK); rotationLine->InsertPoint(3, meanPos); rotationLine->InsertPoint(4, fourthPointTransformedMITK); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = this->m_Controls->m_prefix->text() + "RotationLineNumber" + QString::number(i); newNode->SetName(nodeName.toStdString()); newNode->SetData(rotationLine); newNode->SetBoolProperty("show contour", true); newNode->SetFloatProperty("pointsize", 0.5); this->GetDataStorage()->Add(newNode); } } void QmitkIGTTrackingDataEvaluationView::OnGenerateGroundTruthPointSet() { mitk::PointSet::Pointer generatedPointSet = mitk::PointSet::New(); int currentPointID = 0; mitk::Point3D currentPoint; mitk::FillVector3D(currentPoint, 0, 0, 0); for (int i = 0; i < m_Controls->m_PointNumber2->value(); i++) { for (int j = 0; j < m_Controls->m_PointNumber1->value(); j++) { generatedPointSet->InsertPoint(currentPointID, currentPoint); currentPointID++; currentPoint[1] += m_Controls->m_PointDistance->value(); } currentPoint[1] = 0; currentPoint[2] += m_Controls->m_PointDistance->value(); } mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString nodeName = "GroundTruthPointSet_" + QString::number(m_Controls->m_PointNumber1->value()) + "x" + QString::number(m_Controls->m_PointNumber2->value()) + "_(" + QString::number(m_Controls->m_PointDistance->value()) + "mm)"; newNode->SetName(nodeName.toStdString()); newNode->SetData(generatedPointSet); newNode->SetFloatProperty("pointsize", 5); this->GetDataStorage()->Add(newNode); } void QmitkIGTTrackingDataEvaluationView::OnConvertCSVtoXMLFile() { if (m_Controls->m_ConvertSingleFile->isChecked()) { //convert one file int lines = ConvertOneFile(this->m_Controls->m_InputCSV->text().toStdString(), this->m_Controls->m_OutputXML->text().toStdString()); QString result = "Converted one file with" + QString::number(lines) + " data sets"; MessageBox(result.toStdString()); } else //converte file list { if (m_CSVtoXMLInputFilenameVector.empty() || m_CSVtoXMLOutputFilenameVector.empty()) { MessageBox("Error: one list is not loaded!"); return; } else if (m_CSVtoXMLInputFilenameVector.size() != m_CSVtoXMLOutputFilenameVector.size()) { MessageBox("Error: lists do not have the same number of files!"); return; } for (std::size_t i = 0; i < m_CSVtoXMLInputFilenameVector.size(); ++i) { ConvertOneFile(m_CSVtoXMLInputFilenameVector.at(i), m_CSVtoXMLOutputFilenameVector.at(i)); } QString result = "Converted " + QString::number(m_CSVtoXMLInputFilenameVector.size()) + " files from file list!"; MessageBox(result.toStdString()); } } int QmitkIGTTrackingDataEvaluationView::ConvertOneFile(std::string inputFilename, std::string outputFilename) { std::vector myNavigationDatas = GetNavigationDatasFromFile(inputFilename); mitk::NavigationDataRecorderDeprecated::Pointer myRecorder = mitk::NavigationDataRecorderDeprecated::New(); myRecorder->SetFileName(outputFilename.c_str()); mitk::NavigationData::Pointer input = mitk::NavigationData::New(); if (m_Controls->m_ConvertCSV->isChecked()) myRecorder->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); myRecorder->AddNavigationData(input); myRecorder->StartRecording(); for (std::size_t i = 0; i < myNavigationDatas.size(); ++i) { input->Graft(myNavigationDatas.at(i)); myRecorder->Update(); } myRecorder->StopRecording(); return myNavigationDatas.size(); } void QmitkIGTTrackingDataEvaluationView::OnCSVtoXMLLoadInputList() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLInputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLInputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::OnCSVtoXMLLoadOutputList() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_CSVtoXMLOutputFilenameVector = this->GetFileContentLineByLine(filename.toStdString()); m_Controls->m_labelCSVtoXMLOutputList->setText("READY"); } void QmitkIGTTrackingDataEvaluationView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingDataEvaluationView::WriteHeader() { m_CurrentWriteFile << "Filename;"; m_CurrentWriteFile << "N;"; m_CurrentWriteFile << "N_invalid;"; m_CurrentWriteFile << "Percentage_invalid;"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << "Position_Mean[x];"; m_CurrentWriteFile << "Position_Mean[y];"; m_CurrentWriteFile << "Position_Mean[z];"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << "Position_StandDev[x];"; m_CurrentWriteFile << "Position_StandDev[y];"; m_CurrentWriteFile << "Position_StandDev[z];"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << "Position_SampleStandDev[x];"; m_CurrentWriteFile << "Position_SampleStandDev[y];"; m_CurrentWriteFile << "Position_SampleStandDev[z];"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << "Quaternion_Mean[qx];"; m_CurrentWriteFile << "Quaternion_Mean[qy];"; m_CurrentWriteFile << "Quaternion_Mean[qz];"; m_CurrentWriteFile << "Quaternion_Mean[qr];"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << "Quaternion_StandDev[qx];"; m_CurrentWriteFile << "Quaternion_StandDev[qy];"; m_CurrentWriteFile << "Quaternion_StandDev[qz];"; m_CurrentWriteFile << "Quaternion_StandDev[qr];"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << "PositionError_Mean;"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << "PositionError_StandDev;"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << "PositionError_SampleStandDev;"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << "PositionError_RMS;"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << "PositionError_Median;"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << "PositionError_Max;"; m_CurrentWriteFile << "PositionError_Min;"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << "Euler_tx;"; m_CurrentWriteFile << "Euler_ty;"; m_CurrentWriteFile << "Euler_tz;"; } if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << "EulerErrorRMS (rad);"; m_CurrentWriteFile << "EulerErrorRMS (grad);"; } m_CurrentWriteFile << "\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter, std::string dataSetName) { if (myEvaluationFilter->GetNumberOfOutputs() == 0) m_CurrentWriteFile << "Error: no input \n"; else { m_CurrentWriteFile << dataSetName << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfAnalysedNavigationData(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetNumberOfInvalidSamples(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPercentageOfInvalidSamples(0) << ";"; if (m_Controls->m_settingPosMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionMean(0)[2] << ";"; } if (m_Controls->m_settingPosStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingPosSampleStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionSampleStandardDeviation(0)[2] << ";"; } if (m_Controls->m_settingQuaternionMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionMean(0).r() << ";"; } if (m_Controls->m_settionQuaternionStabw->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).x() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).y() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).z() << ";"; m_CurrentWriteFile << myEvaluationFilter->GetQuaternionStandardDeviation(0).r() << ";"; } if (m_Controls->m_settingPosErrorMean->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMean(0) << ";"; if (m_Controls->m_settingPosErrorStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorSampleStabw->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorSampleStandardDeviation(0) << ";"; if (m_Controls->m_settingPosErrorRMS->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorRMS(0) << ";"; if (m_Controls->m_settingPosErrorMedian->isChecked()) m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMedian(0) << ";"; if (m_Controls->m_settingPosErrorMinMax->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMax(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetPositionErrorMin(0) << ";"; } if (m_Controls->m_settingEulerMean->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[0] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[1] << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesMean(0)[2] << ";"; } if (m_Controls->m_settingEulerRMS->isChecked()) { m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMS(0) << ";"; m_CurrentWriteFile << myEvaluationFilter->GetEulerAnglesRMSDegree(0) << ";"; } m_CurrentWriteFile << "\n"; } } std::vector QmitkIGTTrackingDataEvaluationView::GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP) { std::vector returnValue; for (auto dataSet : allData) { if (useSLERP) returnValue.push_back(GetSLERPAverage(dataSet)); else returnValue.push_back(dataSet->GetQuaternionMean(0)); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetAllDataFromUIList() { std::vector EvaluationDataCollection; //start loop and iterate through all files of list: store the evaluation data for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { //create navigation data player mitk::NavigationDataCSVSequentialPlayer::Pointer myPlayer = ConstructNewNavigationDataPlayer(); myPlayer->SetFiletype(mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV); myPlayer->SetFileName(m_FilenameVector.at(i)); //create evaluation filter mitk::NavigationDataEvaluationFilter::Pointer myEvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); //connect pipeline for (unsigned int j = 0; j < myPlayer->GetNumberOfOutputs(); ++j) myEvaluationFilter->SetInput(j, myPlayer->GetOutput(j)); //update pipline until number of samlples is reached for (int j = 0; j < m_Controls->m_NumberOfSamples->value(); ++j) myEvaluationFilter->Update(); myEvaluationFilter->SetInput(nullptr); myPlayer = nullptr; EvaluationDataCollection.push_back(myEvaluationFilter); } return EvaluationDataCollection; } void QmitkIGTTrackingDataEvaluationView::CalculateDifferenceAngles() { //Get all data from UI std::vector EvaluationDataCollection = GetAllDataFromUIList(); //calculation and writing of output data //open output file m_CurrentAngleDifferencesWriteFile.open(std::string((m_Controls->m_OutputFilename->text() + ".angledifferences.csv").toUtf8()).c_str(), std::ios::out); if (m_CurrentAngleDifferencesWriteFile.bad()) { MessageBox("Error: Can't open output file for angle differences calculation!"); return; } //write header WriteDifferenceAnglesHeader(); //compute angle differences QString pos1 = "invalid"; QString pos2 = "invalid"; //now iterate through all evaluation data and calculate the angles for (std::size_t i = 0; i < m_FilenameVector.size(); ++i) { pos1 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(i))); for (std::size_t j = 0; j < m_FilenameVector.size(); ++j) { pos2 = QString::fromStdString(itksys::SystemTools::GetFilenameWithoutLastExtension(m_FilenameVector.at(j))); mitk::Quaternion q1; mitk::Quaternion q2; if (m_Controls->m_DifferencesSLERP->isChecked()) { //compute slerp average q1 = GetSLERPAverage(EvaluationDataCollection.at(i)); q2 = GetSLERPAverage(EvaluationDataCollection.at(j)); } else { //compute arithmetic average q1 = EvaluationDataCollection.at(i)->GetQuaternionMean(0); q2 = EvaluationDataCollection.at(j)->GetQuaternionMean(0); } itk::Vector rotationVec; //adapt for Aurora 5D tools: [0,0,1000] rotationVec[0] = 10000; //X rotationVec[1] = 0; //Y rotationVec[2] = 0; //Z double AngleBetweenTwoQuaternions = mitk::StaticIGTHelperFunctions::GetAngleBetweenTwoQuaterions(q1, q2, rotationVec); //write data set WriteDifferenceAnglesDataSet(pos1.toStdString(), pos2.toStdString(), i, j, AngleBetweenTwoQuaternions); } } //close output file m_CurrentAngleDifferencesWriteFile.close(); } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesHeader() { m_CurrentAngleDifferencesWriteFile << "Name;Idx1;Idx2;Angle [Degree]\n"; } void QmitkIGTTrackingDataEvaluationView::WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle) { m_CurrentAngleDifferencesWriteFile << "Angle between " << pos1 << " and " << pos2 << ";" << idx1 << ";" << idx2 << ";" << angle << "\n"; MITK_INFO << "Angle: " << angle; } std::vector QmitkIGTTrackingDataEvaluationView::GetNavigationDatasFromFile(std::string filename) { std::vector returnValue = std::vector(); std::vector fileContentLineByLine = GetFileContentLineByLine(filename); for (std::size_t i = 1; i < fileContentLineByLine.size(); ++i) //skip header so start at 1 { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); } return returnValue; } std::vector QmitkIGTTrackingDataEvaluationView::GetFileContentLineByLine(std::string filename) { std::vector readData = std::vector(); //save old locale char * oldLocale; oldLocale = setlocale(LC_ALL, nullptr); //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line if (buffer.size() > 0) readData.push_back(buffer); } } file.close(); //switch back to old locale setlocale(LC_ALL, oldLocale); return readData; } mitk::NavigationData::Pointer QmitkIGTTrackingDataEvaluationView::GetNavigationDataOutOfOneLine(std::string line) { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); QString myLine = QString(line.c_str()); QStringList myLineList = myLine.split(';'); mitk::Point3D position; mitk::Quaternion orientation; bool valid = false; if (myLineList.at(2).toStdString() == "1") valid = true; position[0] = myLineList.at(3).toDouble(); position[1] = myLineList.at(4).toDouble(); position[2] = myLineList.at(5).toDouble(); orientation[0] = myLineList.at(6).toDouble(); orientation[1] = myLineList.at(7).toDouble(); orientation[2] = myLineList.at(8).toDouble(); orientation[3] = myLineList.at(9).toDouble(); returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } mitk::Quaternion QmitkIGTTrackingDataEvaluationView::GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter) { mitk::Quaternion average; //build a vector of quaternions from the evaulation filter (caution always takes the first (0) input of the filter std::vector quaternions = std::vector(); for (int i = 0; i < evaluationFilter->GetNumberOfAnalysedNavigationData(0); i++) { mitk::Quaternion currentq = evaluationFilter->GetLoggedOrientation(i, 0); quaternions.push_back(currentq); } //compute the slerp average using the quaternion averaging class mitk::QuaternionAveraging::Pointer myAverager = mitk::QuaternionAveraging::New(); average = myAverager->CalcAverage(quaternions); return average; } void QmitkIGTTrackingDataEvaluationView::writeToFile(std::string filename, std::vector values) { std::fstream currentFile; currentFile.open(filename.c_str(), std::ios::out); if (currentFile.bad()) { MITK_WARN << "Cannot open file, aborting!"; return; } currentFile << "Description" << ";" << "Error[mm]" << "\n"; for (auto currentError : values) { currentFile << currentError.description << ";" << currentError.distanceError << "\n"; } currentFile.close(); } mitk::NavigationDataCSVSequentialPlayer::Pointer QmitkIGTTrackingDataEvaluationView::ConstructNewNavigationDataPlayer() { bool rightHanded = m_Controls->m_RigthHanded->isChecked(); QString separator = m_Controls->m_SeparatorSign->text(); QChar sepaSign = separator.at(0); //char separatorSign; char separatorSign = sepaSign.toLatin1(); //std::string separatorSign = m_Controls->m_SeparatorSign->text().toStdString(); int sampleCount = m_Controls->m_SampleCount->value(); bool headerRow = m_Controls->m_HeaderRow->isChecked(); int xPos = m_Controls->m_XPos->value(); int yPos = m_Controls->m_YPos->value(); int zPos = m_Controls->m_ZPos->value(); bool useQuats = m_Controls->m_UseQuats->isChecked(); int qx = m_Controls->m_Qx->value(); int qy = m_Controls->m_Qy->value(); int qz = m_Controls->m_Qz->value(); int qr = m_Controls->m_Qr->value(); int azimuth = m_Controls->m_Azimuth->value(); int elevation = m_Controls->m_Elevation->value(); int roll = m_Controls->m_Roll->value(); bool eulersInRad = m_Controls->m_Radiants->isChecked(); //need to find the biggest column number to determine the minimal number of columns the .csv file has to have int allInts[] = {xPos, yPos, zPos, qx, qy, qr, azimuth, elevation, roll}; int minNumberOfColumns = (*std::max_element(allInts, allInts+9)+1); //size needs to be +1 because columns start at 0 but size at 1 mitk::NavigationDataCSVSequentialPlayer::Pointer navDataPlayer = mitk::NavigationDataCSVSequentialPlayer::New(); navDataPlayer->SetOptions(rightHanded, separatorSign, sampleCount, headerRow, xPos, yPos, zPos, useQuats, qx, qy, qz, qr, azimuth, elevation, roll, eulersInRad, minNumberOfColumns); return navDataPlayer; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h index f17462c71e..51865eb5f1 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingDataEvaluationView.h @@ -1,142 +1,143 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkIGTTrackingDataEvaluationView_h #define QmitkIGTTrackingDataEvaluationView_h #include #include +#include #include "ui_QmitkIGTTrackingDataEvaluationViewControls.h" #include "mitkHummelProtocolEvaluation.h" #include #include "mitkNavigationDataCSVSequentialPlayer.h" /*! \brief QmitkIGTTrackingDataEvaluationView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkIGTTrackingDataEvaluationView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkIGTTrackingDataEvaluationView(); ~QmitkIGTTrackingDataEvaluationView() override; void CreateQtPartControl(QWidget *parent) override; - void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) override; - void StdMultiWidgetNotAvailable() override; + virtual void MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) override; + virtual void MultiWidgetNotAvailable() override; protected slots: void OnLoadFileList(); void OnAddToCurrentList(); void OnEvaluateData(); void OnEvaluateDataAll(); void OnGeneratePointSet(); void OnGeneratePointSetsOfSinglePositions(); void OnGenerateRotationLines(); void OnGenerateGroundTruthPointSet(); void OnConvertCSVtoXMLFile(); void OnCSVtoXMLLoadInputList(); void OnCSVtoXMLLoadOutputList(); void OnPerfomGridMatching(); void OnComputeRotation(); /** Reads in exactly three position files als reference. */ void OnOrientationCalculation_CalcRef(); /** Uses always three positions (1,2,3: first orientation; 4,5,6: second orientation; and so on) in every file to calcualte a orientation. */ void OnOrientationCalculation_CalcOrientandWriteToFile(); protected: Ui::QmitkIGTTrackingDataEvaluationViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; std::vector m_FilenameVector; void MessageBox(std::string s); std::fstream m_CurrentWriteFile; void WriteHeader(); void WriteDataSet(mitk::NavigationDataEvaluationFilter::Pointer evaluationFilter, std::string dataSetName); //members for orientation calculation mitk::Point3D m_RefPoint1; mitk::Point3D m_RefPoint2; mitk::Point3D m_RefPoint3; double m_scalingfactor; //scaling factor for visualization, 1 by default //angle diffrences: seperated file std::fstream m_CurrentAngleDifferencesWriteFile; void CalculateDifferenceAngles(); void WriteDifferenceAnglesHeader(); void WriteDifferenceAnglesDataSet(std::string pos1, std::string pos2, int idx1, int idx2, double angle); void writeToFile(std::string filename, std::vector values); //different help methods to read a csv logging file std::vector GetNavigationDatasFromFile(std::string filename); std::vector GetFileContentLineByLine(std::string filename); mitk::NavigationData::Pointer GetNavigationDataOutOfOneLine(std::string line); //help method to sonstruct the NavigationDataCSVSequentialPlayer filled with all the options from the UI mitk::NavigationDataCSVSequentialPlayer::Pointer ConstructNewNavigationDataPlayer(); //CSV to XML members std::vector m_CSVtoXMLInputFilenameVector; std::vector m_CSVtoXMLOutputFilenameVector; //returns the number of converted lines int ConvertOneFile(std::string inputFilename, std::string outputFilename); /** @brief calculates the angle in the plane perpendicular to the rotation axis of the two quaterions. */ double GetAngleBetweenTwoQuaterions(mitk::Quaternion a, mitk::Quaternion b); /** @brief calculates the slerp average of a set of quaternions which is stored in the navigation data evaluation filter */ mitk::Quaternion GetSLERPAverage(mitk::NavigationDataEvaluationFilter::Pointer); /** @brief Stores the mean positions of all evaluated data */ mitk::PointSet::Pointer m_PointSetMeanPositions; /** @return returns the mean orientation of all given data */ std::vector GetMeanOrientationsOfAllData(std::vector allData, bool useSLERP = false); /** @return returns all data read from the data list as NavigationDataEvaluationFilters */ std::vector GetAllDataFromUIList(); }; #endif // _QMITKIGTTRACKINGDATAEVALUATIONVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp index fa2bb0f619..79ae5c0759 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.cpp @@ -1,623 +1,622 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingSemiAutomaticMeasurementView.h" -#include "QmitkStdMultiWidget.h" // Qt #include #include #include #include // MITK #include #include #include #include "mitkHummelProtocolEvaluation.h" // POCO #include #include const std::string QmitkIGTTrackingSemiAutomaticMeasurementView::VIEW_ID = "org.mitk.views.igttrackingsemiautomaticmeasurement"; QmitkIGTTrackingSemiAutomaticMeasurementView::QmitkIGTTrackingSemiAutomaticMeasurementView() : QmitkFunctionality() , m_Controls(nullptr) , m_MultiWidget(nullptr) { m_NextFile = 0; m_FilenameVector = std::vector(); m_Timer = new QTimer(this); m_logging = false; m_referenceValid = true; m_tracking = false; m_EvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); } QmitkIGTTrackingSemiAutomaticMeasurementView::~QmitkIGTTrackingSemiAutomaticMeasurementView() { } void QmitkIGTTrackingSemiAutomaticMeasurementView::CreateResults() { QString LogFileName = m_Controls->m_OutputPath->text() + "_results.log"; mitk::LoggingBackend::Unregister(); mitk::LoggingBackend::SetLogFile(LogFileName.toStdString().c_str()); mitk::LoggingBackend::Register(); double RMSmean = 0; for (std::size_t i = 0; i < m_RMSValues.size(); ++i) { MITK_INFO << "RMS at " << this->m_FilenameVector.at(i) << ": " << m_RMSValues.at(i); RMSmean += m_RMSValues.at(i); } RMSmean /= m_RMSValues.size(); MITK_INFO << "RMS mean over " << m_RMSValues.size() << " values: " << RMSmean; mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName("Tracking Results"); newNode->SetData(this->m_MeanPoints); this->GetDataStorage()->Add(newNode); std::vector results5cmDistances; if (m_Controls->m_mediumVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::medium, results5cmDistances); else if (m_Controls->m_smallVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::small, results5cmDistances); else if (m_Controls->m_standardVolume->isChecked()) mitk::HummelProtocolEvaluation::Evaluate5cmDistances(m_MeanPoints, mitk::HummelProtocolEvaluation::standard, results5cmDistances); } void QmitkIGTTrackingSemiAutomaticMeasurementView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIGTTrackingSemiAutomaticMeasurementViewControls; m_Controls->setupUi(parent); //buttons connect(m_Controls->m_LoadMeasurementToolStorage, SIGNAL(clicked()), this, SLOT(OnLoadMeasurementStorage())); connect(m_Controls->m_LoadReferenceToolStorage, SIGNAL(clicked()), this, SLOT(OnLoadReferenceStorage())); connect(m_Controls->m_StartTracking, SIGNAL(clicked()), this, SLOT(OnStartTracking())); connect(m_Controls->m_LoadList, SIGNAL(clicked()), this, SLOT(OnMeasurementLoadFile())); connect(m_Controls->m_StartNextMeasurement, SIGNAL(clicked()), this, SLOT(StartNextMeasurement())); connect(m_Controls->m_ReapeatLastMeasurement, SIGNAL(clicked()), this, SLOT(RepeatLastMeasurement())); connect(m_Controls->m_SetReference, SIGNAL(clicked()), this, SLOT(OnSetReference())); connect(m_Controls->m_UseReferenceTrackingSystem, SIGNAL(toggled(bool)), this, SLOT(OnUseReferenceToggled(bool))); connect(m_Controls->m_CreateResults, SIGNAL(clicked()), this, SLOT(CreateResults())); //event filter qApp->installEventFilter(this); //timers connect(m_Timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); } //initialize some view m_Controls->m_StopTracking->setEnabled(false); } -void QmitkIGTTrackingSemiAutomaticMeasurementView::StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) +void QmitkIGTTrackingSemiAutomaticMeasurementView::MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) { - m_MultiWidget = &stdMultiWidget; + m_MultiWidget = dynamic_cast(&multiWidget); +} + +void QmitkIGTTrackingSemiAutomaticMeasurementView::MultiWidgetNotAvailable() +{ + m_MultiWidget = nullptr; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnUseReferenceToggled(bool state) { if (state) { m_Controls->m_ReferenceBox->setEnabled(true); m_Controls->m_SetReference->setEnabled(true); } else { m_Controls->m_ReferenceBox->setEnabled(false); m_Controls->m_SetReference->setEnabled(false); } } -void QmitkIGTTrackingSemiAutomaticMeasurementView::StdMultiWidgetNotAvailable() -{ - m_MultiWidget = nullptr; -} - mitk::NavigationToolStorage::Pointer QmitkIGTTrackingSemiAutomaticMeasurementView::ReadStorage(std::string file) { mitk::NavigationToolStorage::Pointer returnValue; //initialize tool storage returnValue = mitk::NavigationToolStorage::New(); //read tool storage from disk mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); returnValue = myDeserializer->Deserialize(file); if (returnValue.IsNull()) { QMessageBox msgBox; msgBox.setText(myDeserializer->GetErrorMessage().c_str()); msgBox.exec(); returnValue = nullptr; } return returnValue; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnSetReference() { //initialize reference m_ReferenceStartPositions = std::vector(); m_ReferenceTrackingDeviceSource->Update(); QString Label = "Positions At Start: "; for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { mitk::Point3D position = m_ReferenceTrackingDeviceSource->GetOutput(i)->GetPosition(); Label = Label + "Tool" + QString::number(i) + ":[" + QString::number(position[0]) + ":" + QString::number(position[1]) + ":" + QString::number(position[1]) + "] "; m_ReferenceStartPositions.push_back(position); } m_Controls->m_ReferencePosAtStart->setText(Label); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnLoadMeasurementStorage() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Toolfile"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; m_MeasurementStorage = ReadStorage(filename.toStdString()); //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Tool Storage: ") + QString::number(m_MeasurementStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_MeasurementToolStorageLabel->setText(toolLabel); //update status widget m_Controls->m_ToolStatusWidget->RemoveStatusLabels(); m_Controls->m_ToolStatusWidget->PreShowTools(m_MeasurementStorage); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnLoadReferenceStorage() { //read in filename static QString oldFile; if (oldFile.isNull()) oldFile = "/"; QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Toolfile"), oldFile, tr("All Files (*.*)")); if (filename.isNull()) return; oldFile = filename; m_ReferenceStorage = ReadStorage(filename.toStdString()); //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Tool Storage: ") + QString::number(m_ReferenceStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_ReferenceToolStorageLabel->setText(toolLabel); } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnStartTracking() { //check if everything is ready to start tracking if (m_MeasurementStorage.IsNull()) { MessageBox("Error: No measurement tools loaded yet!"); return; } else if (m_ReferenceStorage.IsNull() && m_Controls->m_UseReferenceTrackingSystem->isChecked()) { MessageBox("Error: No refernce tools loaded yet!"); return; } else if (m_MeasurementStorage->GetToolCount() == 0) { MessageBox("Error: No way to track without tools!"); return; } else if (m_Controls->m_UseReferenceTrackingSystem->isChecked() && (m_ReferenceStorage->GetToolCount() == 0)) { MessageBox("Error: No way to track without tools!"); return; } //build the first IGT pipeline (MEASUREMENT) mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory1 = mitk::TrackingDeviceSourceConfigurator::New(this->m_MeasurementStorage, this->m_Controls->m_MeasurementTrackingDeviceConfigurationWidget->GetTrackingDevice()); m_MeasurementTrackingDeviceSource = myTrackingDeviceSourceFactory1->CreateTrackingDeviceSource(this->m_MeasurementToolVisualizationFilter); if (m_MeasurementTrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory1->GetErrorMessage()); return; } //connect the tool visualization widget for (unsigned int i = 0; i < m_MeasurementTrackingDeviceSource->GetNumberOfOutputs(); ++i) { m_Controls->m_ToolStatusWidget->AddNavigationData(m_MeasurementTrackingDeviceSource->GetOutput(i)); m_EvaluationFilter->SetInput(i, m_MeasurementTrackingDeviceSource->GetOutput(i)); } m_Controls->m_ToolStatusWidget->ShowStatusLabels(); m_Controls->m_ToolStatusWidget->SetShowPositions(true); m_Controls->m_ToolStatusWidget->SetShowQuaternions(true); //build the second IGT pipeline (REFERENCE) if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory2 = mitk::TrackingDeviceSourceConfigurator::New(this->m_ReferenceStorage, this->m_Controls->m_ReferenceDeviceConfigurationWidget->GetTrackingDevice()); m_ReferenceTrackingDeviceSource = myTrackingDeviceSourceFactory2->CreateTrackingDeviceSource(); if (m_ReferenceTrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory2->GetErrorMessage()); return; } } //initialize tracking try { m_MeasurementTrackingDeviceSource->Connect(); m_MeasurementTrackingDeviceSource->StartTracking(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Connect(); m_ReferenceTrackingDeviceSource->StartTracking(); } } catch (...) { MessageBox("Error while starting the tracking device!"); return; } //set reference if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) OnSetReference(); //start timer m_Timer->start(1000 / (m_Controls->m_SamplingRate->value())); m_Controls->m_StartTracking->setEnabled(false); m_Controls->m_StartTracking->setEnabled(true); m_tracking = true; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnStopTracking() { if (this->m_logging) FinishMeasurement(); m_MeasurementTrackingDeviceSource->Disconnect(); m_MeasurementTrackingDeviceSource->StopTracking(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Disconnect(); m_ReferenceTrackingDeviceSource->StopTracking(); } m_Timer->stop(); m_Controls->m_StartTracking->setEnabled(true); m_Controls->m_StartTracking->setEnabled(false); m_tracking = false; } void QmitkIGTTrackingSemiAutomaticMeasurementView::OnMeasurementLoadFile() { m_FilenameVector = std::vector(); m_FilenameVector.clear(); m_NextFile = 0; //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Measurement Filename List"), "/", tr("All Files (*.*)")); if (filename.isNull()) return; //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.toStdString().c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line if (buffer.size() > 0) m_FilenameVector.push_back(buffer); } } //fill list at GUI m_Controls->m_MeasurementList->clear(); for (unsigned int i = 0; i < m_FilenameVector.size(); i++) { new QListWidgetItem(tr(m_FilenameVector.at(i).c_str()), m_Controls->m_MeasurementList); } //update label next measurement std::stringstream label; label << "Next Measurement: " << m_FilenameVector.at(0); m_Controls->m_NextMeasurement->setText(label.str().c_str()); //reset results files m_MeanPoints = mitk::PointSet::New(); m_RMSValues = std::vector(); m_EvaluationFilter = mitk::NavigationDataEvaluationFilter::New(); if (m_MeasurementToolVisualizationFilter.IsNotNull()) m_EvaluationFilter->SetInput(0, m_MeasurementToolVisualizationFilter->GetOutput(0)); } void QmitkIGTTrackingSemiAutomaticMeasurementView::UpdateTimer() { if (m_EvaluationFilter.IsNotNull() && m_logging) m_EvaluationFilter->Update(); else m_MeasurementToolVisualizationFilter->Update(); m_Controls->m_ToolStatusWidget->Refresh(); //update reference if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceTrackingDeviceSource->Update(); QString Label = "Current Positions: "; bool distanceThresholdExceeded = false; for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { mitk::Point3D position = m_ReferenceTrackingDeviceSource->GetOutput(i)->GetPosition(); Label = Label + "Tool" + QString::number(i) + ":[" + QString::number(position[0]) + ":" + QString::number(position[1]) + ":" + QString::number(position[1]) + "] "; if (position.EuclideanDistanceTo(m_ReferenceStartPositions.at(i)) > m_Controls->m_ReferenceThreshold->value()) distanceThresholdExceeded = true; } m_Controls->m_ReferenceCurrentPos->setText(Label); if (distanceThresholdExceeded) { m_Controls->m_ReferenceOK->setText("NOT OK!"); m_referenceValid = false; } else { m_Controls->m_ReferenceOK->setText("OK"); m_referenceValid = true; } } //update logging if (m_logging) { //check for missing objects if (m_MeasurementLoggingFilterXML.IsNull() || m_MeasurementLoggingFilterCSV.IsNull() ) { return; } //log/measure m_MeasurementLoggingFilterXML->Update(); m_MeasurementLoggingFilterCSV->Update(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked() && m_ReferenceLoggingFilterXML.IsNotNull() && m_ReferenceLoggingFilterCSV.IsNotNull()) { m_ReferenceLoggingFilterXML->Update(); m_ReferenceLoggingFilterCSV->Update(); } m_loggedFrames++; LogAdditionalCSVFile(); //check if all frames are logged ... if yes finish the measurement if (m_loggedFrames > m_Controls->m_SamplesPerMeasurement->value()) { FinishMeasurement(); } //update logging label QString loggingLabel = "Collected Samples: " + QString::number(m_loggedFrames); m_Controls->m_CollectedSamples->setText(loggingLabel); } } void QmitkIGTTrackingSemiAutomaticMeasurementView::StartNextMeasurement() { if (this->m_NextFile >= static_cast(m_FilenameVector.size())) { MessageBox("Last Measurement reached!"); return; } m_loggedFrames = 0; m_logging = true; //check if directory exists, if not create one Poco::File myPath(std::string(m_Controls->m_OutputPath->text().toUtf8()).c_str()); if (!myPath.exists()) myPath.createDirectory(); QString LogFileName = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".log"; mitk::LoggingBackend::Unregister(); mitk::LoggingBackend::SetLogFile(LogFileName.toStdString().c_str()); mitk::LoggingBackend::Register(); //initialize logging filters m_MeasurementLoggingFilterXML = mitk::NavigationDataRecorderDeprecated::New(); m_MeasurementLoggingFilterXML->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_MeasurementLoggingFilterCSV = mitk::NavigationDataRecorderDeprecated::New(); m_MeasurementLoggingFilterCSV->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_MeasurementLoggingFilterXML->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::xml); m_MeasurementLoggingFilterCSV->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); QString MeasurementFilenameXML = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".xml"; QString MeasurementFilenameCSV = m_Controls->m_OutputPath->text() + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".csv"; m_MeasurementLoggingFilterXML->SetFileName(MeasurementFilenameXML.toStdString()); m_MeasurementLoggingFilterCSV->SetFileName(MeasurementFilenameCSV.toStdString()); m_MeasurementLoggingFilterXML->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); m_MeasurementLoggingFilterCSV->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML = mitk::NavigationDataRecorderDeprecated::New(); m_ReferenceLoggingFilterXML->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_ReferenceLoggingFilterCSV = mitk::NavigationDataRecorderDeprecated::New(); m_ReferenceLoggingFilterCSV->SetRecordingMode(mitk::NavigationDataRecorderDeprecated::NormalFile); m_ReferenceLoggingFilterXML->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::xml); m_ReferenceLoggingFilterCSV->SetOutputFormat(mitk::NavigationDataRecorderDeprecated::csv); QString ReferenceFilenameXML = m_Controls->m_OutputPath->text() + "Reference_" + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".xml"; QString ReferenceFilenameCSV = m_Controls->m_OutputPath->text() + "Reference_" + QString(m_FilenameVector.at(m_NextFile).c_str()) + ".csv"; m_ReferenceLoggingFilterXML->SetFileName(ReferenceFilenameXML.toStdString()); m_ReferenceLoggingFilterCSV->SetFileName(ReferenceFilenameCSV.toStdString()); m_ReferenceLoggingFilterXML->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); m_ReferenceLoggingFilterCSV->SetRecordCountLimit(m_Controls->m_SamplesPerMeasurement->value()); } //start additional csv logging StartLoggingAdditionalCSVFile(m_FilenameVector.at(m_NextFile)); //connect filter for (unsigned int i = 0; i < m_MeasurementToolVisualizationFilter->GetNumberOfOutputs(); ++i) { m_MeasurementLoggingFilterXML->AddNavigationData(m_MeasurementToolVisualizationFilter->GetOutput(i)); m_MeasurementLoggingFilterCSV->AddNavigationData(m_MeasurementToolVisualizationFilter->GetOutput(i)); } if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) for (unsigned int i = 0; i < m_ReferenceTrackingDeviceSource->GetNumberOfOutputs(); ++i) { m_ReferenceLoggingFilterXML->AddNavigationData(m_ReferenceTrackingDeviceSource->GetOutput(i)); m_ReferenceLoggingFilterCSV->AddNavigationData(m_ReferenceTrackingDeviceSource->GetOutput(i)); } //start filter m_MeasurementLoggingFilterXML->StartRecording(); m_MeasurementLoggingFilterCSV->StartRecording(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML->StartRecording(); m_ReferenceLoggingFilterCSV->StartRecording(); } //disable all buttons DisableAllButtons(); //update label next measurement std::stringstream label; if ((m_NextFile + 1) >= static_cast(m_FilenameVector.size())) label << "Next Measurement: "; else label << "Next Measurement: " << m_FilenameVector.at(m_NextFile + 1); m_Controls->m_NextMeasurement->setText(label.str().c_str()); //update label last measurement std::stringstream label2; label2 << "Last Measurement: " << m_FilenameVector.at(m_NextFile); m_Controls->m_LastMeasurement->setText(label2.str().c_str()); m_NextFile++; } void QmitkIGTTrackingSemiAutomaticMeasurementView::RepeatLastMeasurement() { m_NextFile--; StartNextMeasurement(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::DisableAllButtons() { m_Controls->m_LoadList->setEnabled(false); m_Controls->m_StartNextMeasurement->setEnabled(false); m_Controls->m_ReapeatLastMeasurement->setEnabled(false); m_Controls->m_SamplingRate->setEnabled(false); m_Controls->m_SamplesPerMeasurement->setEnabled(false); m_Controls->m_ReferenceThreshold->setEnabled(false); } void QmitkIGTTrackingSemiAutomaticMeasurementView::EnableAllButtons() { m_Controls->m_LoadList->setEnabled(true); m_Controls->m_StartNextMeasurement->setEnabled(true); m_Controls->m_ReapeatLastMeasurement->setEnabled(true); m_Controls->m_SamplingRate->setEnabled(true); m_Controls->m_SamplesPerMeasurement->setEnabled(true); m_Controls->m_ReferenceThreshold->setEnabled(true); } void QmitkIGTTrackingSemiAutomaticMeasurementView::FinishMeasurement() { m_logging = false; m_MeasurementLoggingFilterXML->StopRecording(); m_MeasurementLoggingFilterCSV->StopRecording(); if (m_Controls->m_UseReferenceTrackingSystem->isChecked()) { m_ReferenceLoggingFilterXML->StopRecording(); m_ReferenceLoggingFilterCSV->StopRecording(); } StopLoggingAdditionalCSVFile(); int id = m_NextFile - 1; mitk::Point3D positionMean = m_EvaluationFilter->GetPositionMean(0); MITK_INFO << "Evaluated " << m_EvaluationFilter->GetNumberOfAnalysedNavigationData(0) << " samples."; double rms = m_EvaluationFilter->GetPositionErrorRMS(0); MITK_INFO << "RMS: " << rms; MITK_INFO << "Position Mean: " << positionMean; m_MeanPoints->SetPoint(id, positionMean); if (static_cast(m_RMSValues.size()) <= id) m_RMSValues.push_back(rms); else m_RMSValues[id] = rms; m_EvaluationFilter->ResetStatistic(); EnableAllButtons(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StartLoggingAdditionalCSVFile(std::string filePostfix) { //write logfile header QString header = "Nr;MITK_Time;Valid_Reference;"; QString tool = QString("MeasureTool_") + QString(m_MeasurementTrackingDeviceSource->GetOutput(0)->GetName()); header = header + tool + "[x];" + tool + "[y];" + tool + "[z];" + tool + "[qx];" + tool + "[qy];" + tool + "[qz];" + tool + "[qr]\n"; //open logfile and write header m_logFileCSV.open(std::string(m_Controls->m_OutputPath->text().toUtf8()).append("/LogFileCombined").append(filePostfix.c_str()).append(".csv").c_str(), std::ios::out); m_logFileCSV << header.toStdString().c_str(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::LogAdditionalCSVFile() { mitk::Point3D pos = m_MeasurementTrackingDeviceSource->GetOutput(0)->GetPosition(); mitk::Quaternion rot = m_MeasurementTrackingDeviceSource->GetOutput(0)->GetOrientation(); std::string valid = ""; if (m_referenceValid) valid = "true"; else valid = "false"; std::stringstream timestamp; timestamp << m_MeasurementTrackingDeviceSource->GetOutput(0)->GetTimeStamp(); QString dataSet = QString::number(m_loggedFrames) + ";" + QString(timestamp.str().c_str()) + ";" + QString(valid.c_str()) + ";" + QString::number(pos[0]) + ";" + QString::number(pos[1]) + ";" + QString::number(pos[2]) + ";" + QString::number(rot.x()) + ";" + QString::number(rot.y()) + ";" + QString::number(rot.z()) + ";" + QString::number(rot.r()) + "\n"; m_logFileCSV << dataSet.toStdString(); } void QmitkIGTTrackingSemiAutomaticMeasurementView::StopLoggingAdditionalCSVFile() { m_logFileCSV.close(); } bool QmitkIGTTrackingSemiAutomaticMeasurementView::eventFilter(QObject *, QEvent *ev) { if (ev->type() == QEvent::KeyPress) { QKeyEvent *k = (QKeyEvent *)ev; bool down = k->key() == 16777239; if (down && m_tracking && !m_logging) StartNextMeasurement(); } return false; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h index 10d51a111a..5b203cc7b8 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/QmitkIGTTrackingSemiAutomaticMeasurementView.h @@ -1,132 +1,133 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkIGTTrackingSemiAutomaticMeasurementView_h #define QmitkIGTTrackingSemiAutomaticMeasurementView_h #include #include +#include //QT #include //MITK #include #include #include #include #include #include "ui_QmitkIGTTrackingSemiAutomaticMeasurementViewControls.h" /*! \brief QmitkIGTTrackingSemiAutomaticMeasurementView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkIGTTrackingSemiAutomaticMeasurementView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkIGTTrackingSemiAutomaticMeasurementView(); ~QmitkIGTTrackingSemiAutomaticMeasurementView() override; void CreateQtPartControl(QWidget *parent) override; - void StdMultiWidgetAvailable(QmitkStdMultiWidget &stdMultiWidget) override; - void StdMultiWidgetNotAvailable() override; + virtual void MultiWidgetAvailable(QmitkAbstractMultiWidget &multiWidget) override; + virtual void MultiWidgetNotAvailable() override; protected slots: void OnLoadMeasurementStorage(); void OnLoadReferenceStorage(); void OnStartTracking(); void OnStopTracking(); void OnMeasurementLoadFile(); void OnSetReference(); void StartNextMeasurement(); void RepeatLastMeasurement(); void UpdateTimer(); void CreateResults(); void OnUseReferenceToggled(bool state); protected: Ui::QmitkIGTTrackingSemiAutomaticMeasurementViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; //the tool storages mitk::NavigationToolStorage::Pointer m_MeasurementStorage; mitk::NavigationToolStorage::Pointer m_ReferenceStorage; //members for the filter pipeline mitk::TrackingDeviceSource::Pointer m_MeasurementTrackingDeviceSource; mitk::NavigationDataObjectVisualizationFilter::Pointer m_MeasurementToolVisualizationFilter; mitk::NavigationDataRecorderDeprecated::Pointer m_MeasurementLoggingFilterXML; mitk::NavigationDataRecorderDeprecated::Pointer m_MeasurementLoggingFilterCSV; mitk::TrackingDeviceSource::Pointer m_ReferenceTrackingDeviceSource; mitk::NavigationDataRecorderDeprecated::Pointer m_ReferenceLoggingFilterXML; mitk::NavigationDataRecorderDeprecated::Pointer m_ReferenceLoggingFilterCSV; //members for file name list std::vector m_FilenameVector; int m_NextFile; //help methods mitk::NavigationToolStorage::Pointer ReadStorage(std::string file); void MessageBox(std::string s); void DisableAllButtons(); void EnableAllButtons(); void FinishMeasurement(); void StartLoggingAdditionalCSVFile(std::string filePostfix); void LogAdditionalCSVFile(); void StopLoggingAdditionalCSVFile(); //timer QTimer* m_Timer; //memebers for reference checking std::vector m_ReferenceStartPositions; bool m_referenceValid; //logging members int m_loggedFrames; bool m_logging; std::fstream m_logFileCSV; //event filter for key presses bool eventFilter(QObject *obj, QEvent *ev) override; //results members mitk::PointSet::Pointer m_MeanPoints; std::vector m_RMSValues; mitk::NavigationDataEvaluationFilter::Pointer m_EvaluationFilter; bool m_tracking; }; #endif // _QMITKIGTTRACKINGSEMIAUTOMATICMEASUREMENTVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp index 54a8e352d3..44a059165e 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation/src/internal/QmitkUSNavigationMarkerPlacement.cpp @@ -1,830 +1,806 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationMarkerPlacement.h" #include "ui_QmitkUSNavigationMarkerPlacement.h" #include "NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h" #include "NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h" #include "NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h" #include "SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h" #include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkIRenderingManager.h" #include "mitkNodeDisplacementFilter.h" #include "mitkTrackedUltrasound.h" #include #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkCameraController.h" #include "mitkLayoutAnnotationRenderer.h" #include // scene serialization #include #include #include #include #include const std::string QmitkUSNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *QmitkUSNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; QmitkUSNavigationMarkerPlacement::QmitkUSNavigationMarkerPlacement() : m_Parent(nullptr), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(nullptr), m_CombinedModality(nullptr), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_CurrentApplicationName(), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_ResultsDirectory(), m_ExperimentName(), m_ExperimentResultsSubDirectory(), m_NavigationStepNames(), m_LoggingBackend(), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_TargetNodeDisplacementFilter(nullptr), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_ToolVisualizationFilter(nullptr), m_AblationZonesVector(), m_NeedleIndex(0), m_MarkerIndex(1), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_NavigationDataSource(nullptr), m_CurrentStorage(nullptr), m_ImageStreamNode(nullptr), ui(new Ui::QmitkUSNavigationMarkerPlacement) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); } QmitkUSNavigationMarkerPlacement::~QmitkUSNavigationMarkerPlacement() { this->GetDataStorage()->Remove(m_InstrumentNode); delete ui; } void QmitkUSNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(newSize / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkSphere->GetOutput()); } void QmitkUSNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSmartPointer vtkSphere = vtkSmartPointer::New(); vtkSphere->SetRadius(size / 2); vtkSphere->SetCenter(0, 0, 0); vtkSphere->SetPhiResolution(20); vtkSphere->SetThetaResolution(20); vtkSphere->Update(); zone->SetVtkPolyData(vtkSphere->GetOutput()); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void QmitkUSNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->m_RenderWindowSelection, SIGNAL(valueChanged(int)), this, SLOT(OnRenderWindowSelection())); connect(ui->m_RefreshView, SIGNAL(clicked()), this, SLOT(OnRefreshView())); m_BaseNode = this->GetDataStorage()->GetNamedNode(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if (m_BaseNode.IsNull()) { m_BaseNode = mitk::DataNode::New(); m_BaseNode->SetName(QmitkUSAbstractNavigationStep::DATANAME_BASENODE); this->GetDataStorage()->Add(m_BaseNode); } connect(ui->m_CtToUsRegistrationWidget, SIGNAL(GetCursorPosition()), this, SLOT(OnGetCursorPosition())); connect(ui->m_CtToUsRegistrationWidget, SIGNAL(ActualizeCtToUsRegistrationWidget()), this, SLOT(OnActualizeCtToUsRegistrationWidget())); connect(ui->m_initializeCtToUsRegistration, SIGNAL(clicked()), this, SLOT(OnInitializeCtToUsRegistration())); connect(ui->m_initializeTargetMarking, SIGNAL(clicked()), this, SLOT(OnInitializeTargetMarking())); connect(ui->m_initializeCritStructureMarking, SIGNAL(clicked()), this, SLOT(OnInitializeCriticalStructureMarking())); connect(ui->m_initializeNavigation, SIGNAL(clicked()), this, SLOT(OnInitializeNavigation())); // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); - connect(ui->m_settingsWidget, - SIGNAL(SettingsChanged(itk::SmartPointer)), - this, - SLOT(OnSettingsChanged(itk::SmartPointer))); + connect(ui->m_settingsWidget, SIGNAL(SettingsChanged(itk::SmartPointer)), + this, SLOT(OnSettingsChanged(itk::SmartPointer))); } void QmitkUSNavigationMarkerPlacement::ReInitializeSettingsNodesAndImageStream() { //If update timer is not stopped (signals stopped), setting the m_CombinedModality // will cause a crash of the workbench in some times. m_UpdateTimer->blockSignals(true); m_UpdateTimer->stop(); m_SettingsNode = mitk::DataNode::New(); ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); InitImageStream(); m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); // Having set the m_CombinedModality reactivate the update timer again m_UpdateTimer->start(50); // every 50 Milliseconds = 20 Frames/Second m_UpdateTimer->blockSignals(false); } void QmitkUSNavigationMarkerPlacement::OnGetCursorPosition() { mitk::Point3D centroid = this->GetRenderWindowPart()->GetSelectedPosition(); ui->m_CtToUsRegistrationWidget->OnCalculateTRE(centroid); } void QmitkUSNavigationMarkerPlacement::OnActualizeCtToUsRegistrationWidget() { m_SettingsNode = mitk::DataNode::New(); ui->m_settingsWidget->OnSetSettingsNode(m_SettingsNode, true); this->InitImageStream(); if (ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality().IsNull()) { return; } ui->m_CtToUsRegistrationWidget->SetCombinedModality( ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality()); m_CombinedModality = ui->m_CombinedModalityCreationWidget->GetSelectedCombinedModality(); if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before - mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); + mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); - QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); + QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { - m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); + m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); + multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } } else { this->OnRefreshView(); } m_UpdateTimer->start(50); // every 50 Milliseconds = 20 Frames/Second } void QmitkUSNavigationMarkerPlacement::OnInitializeCtToUsRegistration() { ui->m_CtToUsRegistrationWidget->SetDataStorage(this->GetDataStorage()); ui->m_CtToUsRegistrationWidget->OnSettingsChanged(m_SettingsNode); ui->m_CtToUsRegistrationWidget->OnActivateStep(); ui->m_CtToUsRegistrationWidget->OnStartStep(); ui->m_CtToUsRegistrationWidget->Update(); } - - void QmitkUSNavigationMarkerPlacement::OnInitializeTargetMarking() { ReInitializeSettingsNodesAndImageStream(); ui->m_TargetMarkingWidget->SetCombinedModality(m_CombinedModality); ui->m_TargetMarkingWidget->SetDataStorage(this->GetDataStorage()); ui->m_TargetMarkingWidget->OnSettingsChanged(m_SettingsNode); ui->m_TargetMarkingWidget->OnActivateStep(); ui->m_TargetMarkingWidget->OnStartStep(); ui->m_TargetMarkingWidget->Update(); } + void QmitkUSNavigationMarkerPlacement::OnInitializeCriticalStructureMarking() { ReInitializeSettingsNodesAndImageStream(); ui->m_CriticalStructuresWidget->SetCombinedModality(m_CombinedModality); ui->m_CriticalStructuresWidget->SetDataStorage(this->GetDataStorage()); ui->m_CriticalStructuresWidget->OnSettingsChanged(m_SettingsNode); ui->m_CriticalStructuresWidget->OnActivateStep(); ui->m_CriticalStructuresWidget->OnStartStep(); ui->m_CriticalStructuresWidget->Update(); } + void QmitkUSNavigationMarkerPlacement::OnInitializeNavigation() { ReInitializeSettingsNodesAndImageStream(); ui->m_NavigationWidget->SetCombinedModality(m_CombinedModality); ui->m_NavigationWidget->SetDataStorage(this->GetDataStorage()); ui->m_NavigationWidget->OnSettingsChanged(m_SettingsNode); ui->m_NavigationWidget->OnActivateStep(); ui->m_NavigationWidget->OnStartStep(); ui->m_NavigationWidget->Update(); // test if it is tracked US, if yes add visualization filter if (m_CombinedModality->GetIsTrackedUltrasoundActive()) { m_InstrumentNode = mitk::DataNode::New(); m_InstrumentNode->SetName("Tracked US Instrument"); m_InstrumentNode->SetData( m_CombinedModality->GetNavigationDataSource()->GetToolMetaData(0)->GetToolSurface()->Clone()); this->GetDataStorage()->Add(m_InstrumentNode); m_ToolVisualizationFilter = mitk::NavigationDataObjectVisualizationFilter::New(); m_ToolVisualizationFilter->ConnectTo(m_CombinedModality->GetNavigationDataSource()); m_ToolVisualizationFilter->SetRepresentationObject(0, m_InstrumentNode->GetData()); //caution: currently hard coded that instrument has id 0 //set dummy objects to avoid spamming of console mitk::Surface::Pointer dummyObject = mitk::Surface::New(); m_ToolVisualizationFilter->SetRepresentationObject(1, dummyObject); m_ToolVisualizationFilter->SetRepresentationObject(2, dummyObject); - } } void QmitkUSNavigationMarkerPlacement::InitImageStream() { if (m_ImageStreamNode.IsNull()) { m_ImageStreamNode = mitk::DataNode::New(); m_ImageStreamNode->SetName("US Navigation Viewing Stream"); this->GetDataStorage()->Add(m_ImageStreamNode); } } void QmitkUSNavigationMarkerPlacement::OnCombinedModalityPropertyChanged(const std::string &key, const std::string &) { if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_ReinitAlreadyDone = false; this->ReinitOnImage(); if (m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsCalibratedForCurrentStatus()) { mitk::LayoutAnnotationRenderer::AddAnnotation( m_WarnOverlay.GetPointer(), "stdmulti.widget1", mitk::LayoutAnnotationRenderer::TopLeft); MITK_WARN << "No calibration available for the selected ultrasound image depth."; } } } void QmitkUSNavigationMarkerPlacement::SetFocus() { this->ReinitOnImage(); } void QmitkUSNavigationMarkerPlacement::OnTimeout() { if (m_CombinedModality.IsNull()) return; m_CombinedModality->Modified(); // shouldn't be nessecary ... fix in abstract ultrasound tracker device! m_CombinedModality->Update(); if (m_ToolVisualizationFilter.IsNotNull()) { m_ToolVisualizationFilter->Update(); } ui->m_CtToUsRegistrationWidget->Update(); ui->m_TargetMarkingWidget->Update(); ui->m_CriticalStructuresWidget->Update(); ui->m_NavigationWidget->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); // make sure that always the current image is set to the data node if (image.IsNotNull() && m_ImageStreamNode->GetData() != image.GetPointer() && image->IsInitialized()) { m_ImageStreamNode->SetData(image); } if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before - mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); + mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); - QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); + QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { - m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); + m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); + multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } this->CreateOverlays(); } if (m_CombinedModality.IsNotNull() && !this->m_CombinedModality->GetIsFreezed()) // if the combined modality is freezed: do nothing { m_AblationZonesDisplacementFilter->Update(); // update the 3D window only every fourth time to speed up the rendering (at least in 2D) this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); // make sure that a reinit was performed on the image this->ReinitOnImage(); } } void QmitkUSNavigationMarkerPlacement::OnEnableNavigationLayout() { MITK_INFO << "Navigation Layout"; // try to get the standard multi widget if it couldn't be got before - mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); + mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); - QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); + QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindowPart); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { - m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); + m_StdMultiWidget = dynamic_cast(multiWidgetEditor->GetMultiWidget()); + multiWidgetEditor->ShowLevelWindowWidget(false); SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::OnRenderWindowSelection() { SetTwoWindowView(); } void QmitkUSNavigationMarkerPlacement::OnRefreshView() { if (!ui->m_enableNavigationLayout->isChecked()) OnResetStandardLayout(); else { // Reinit the US Image Stream (this might be broken if there was a global reinit somewhere...) try { mitk::RenderingManager::GetInstance()->InitializeViews( // Reinit this ->GetDataStorage() // GetDataStorage ->GetNamedNode("US Viewing Stream - Image 0") ->GetData() ->GetTimeGeometry()); // GetNode } catch (...) { MITK_DEBUG << "No reinit possible"; } SetTwoWindowView(); } } void QmitkUSNavigationMarkerPlacement::SetTwoWindowView() { if (m_StdMultiWidget) { - MITK_INFO << "m_StdMultiWidget exists and not null"; - m_StdMultiWidget->DisableStandardLevelWindow(); int i, j, k; switch (this->ui->m_RenderWindowSelection->value()) { case 1: - mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4")) - ->GetCameraController() - ->SetViewToCaudal(); + mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToCaudal(); i = 2; j = 3; // other windows k = 1; break; case 2: - mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4")) - ->GetCameraController() - ->SetViewToSinister(); + mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToSinister(); i = 1; j = 3; k = 2; break; case 3: - mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4")) - ->GetCameraController() - ->SetViewToAnterior(); + mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetCameraController()->SetViewToAnterior(); i = 2; j = 1; k = 3; break; default: return; } - m_StdMultiWidget->changeLayoutTo2DUpAnd3DDown(k); + + // get the render window which is defined by index "k" and set it as "current render window widget" + // chose the layout that will set the current 2D window as top render window and the 3D windows as bottom render window + auto renderWindowWidget = m_StdMultiWidget->GetRenderWindowWidget(m_StdMultiWidget->GetNameFromIndex(k)); + m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetCurrentRenderWindowWidget(renderWindowWidget.get()); + m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetOneTop3DBottomLayout(); + ////Crosshair invisible in 3D view - this->GetDataStorage() - ->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") - ->SetBoolProperty("visible", - false, - mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); - this->GetDataStorage() - ->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") - ->SetBoolProperty("visible", - false, - mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); - this->GetDataStorage() - ->GetNamedNode("stdmulti.widget" + std::to_string(k) + ".plane") - ->SetBoolProperty("visible", - true, - mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); - this->GetDataStorage() - ->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") + this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") + ->SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") + ->SetBoolProperty("visible", false, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(k) + ".plane") + ->SetBoolProperty("visible", true, mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(i) + ".plane") ->SetIntProperty("Crosshair.Gap Size", 0); - this->GetDataStorage() - ->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") + this->GetDataStorage()->GetNamedNode("stdmulti.widget" + std::to_string(j) + ".plane") ->SetIntProperty("Crosshair.Gap Size", 0); } } void QmitkUSNavigationMarkerPlacement::OnResetStandardLayout() { - // reset render windows - mitk::DataNode::Pointer widget1 = this->GetDataStorage()->GetNamedNode("stdmulti.widget1.plane"); - if (widget1.IsNotNull()) - { - widget1->SetVisibility(true); - } - mitk::DataNode::Pointer widget2 = this->GetDataStorage()->GetNamedNode("stdmulti.widget2.plane"); - if (widget2.IsNotNull()) - { - widget2->SetVisibility(true); - } - mitk::DataNode::Pointer widget3 = this->GetDataStorage()->GetNamedNode("stdmulti.widget3.plane"); - if (widget3.IsNotNull()) + if (m_StdMultiWidget) { - widget3->SetVisibility(true); + //reset render windows + m_StdMultiWidget->SetCrosshairVisibility(true); + m_StdMultiWidget->GetMultiWidgetLayoutManager()->SetDefaultLayout(); } - m_StdMultiWidget->changeLayoutToDefault(); } void QmitkUSNavigationMarkerPlacement::OnChangeLayoutClicked() { if (ui->m_enableNavigationLayout->isChecked()) OnEnableNavigationLayout(); else OnResetStandardLayout(); } void QmitkUSNavigationMarkerPlacement::OnImageAndNavigationDataLoggingTimeout() { // update filter for logging navigation data and ultrasound images if (m_CombinedModality.IsNotNull()) { m_NavigationDataRecorder->Update(); // get last messages for logging filer and store them std::vector messages = m_LoggingBackend.GetNavigationMessages(); std::string composedMessage = ""; for (std::size_t i = 0; i < messages.size(); i++) { composedMessage += messages.at(i); } m_USImageLoggingFilter->AddMessageToCurrentImage(composedMessage); m_LoggingBackend.ClearNavigationMessages(); // update logging filter m_USImageLoggingFilter->Update(); } } void QmitkUSNavigationMarkerPlacement::OnStartExperiment() { // get name for the experiment by a QInputDialog bool ok; if (m_ExperimentName.isEmpty()) { // default: current date m_ExperimentName = QString::number(QDateTime::currentDateTime().date().year()) + "_" + QString::number(QDateTime::currentDateTime().date().month()) + "_" + QString::number(QDateTime::currentDateTime().date().day()) + "_experiment_" + QString::number(QDateTime::currentDateTime().time().hour()) + "." + QString::number(QDateTime::currentDateTime().time().minute()); } m_ExperimentName = QInputDialog::getText( m_Parent, QString("Experiment Name"), QString("Name of the Experiment"), QLineEdit::Normal, m_ExperimentName, &ok); MITK_INFO("USNavigationLogging") << "Experiment started: " << m_ExperimentName.toStdString(); if (ok && !m_ExperimentName.isEmpty()) { - // display error message and call the function recursivly if a directory + // display error message and call the function recursively if a directory // with the given name already exists QDir experimentResultsDir(m_ResultsDirectory + QDir::separator() + m_ExperimentName); if (experimentResultsDir.exists()) { QMessageBox::critical( m_Parent, "Results Directory Exists", "The result directory already exists.\nPlease choose an other name."); this->OnStartExperiment(); } else { QDir(m_ResultsDirectory).mkdir(m_ExperimentName); m_ExperimentResultsSubDirectory = m_ResultsDirectory + QDir::separator() + m_ExperimentName; // experiment is running now ui->runningLabel->setPixmap(m_IconRunning); // (re)start timer for navigation step durations m_NavigationStepTimer->Reset(); m_NavigationStepTimer->SetOutputFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("durations.cvs")).toStdString()); m_NavigationStepTimer->SetActiveIndex(0, "Initialization"); ui->finishExperimentButton->setEnabled(true); ui->startExperimentButton->setDisabled(true); // initialize and register logging backend QString loggingFilename = m_ExperimentResultsSubDirectory + QDir::separator() + "logging.txt"; m_LoggingBackend.SetOutputFileName(loggingFilename.toStdString()); mbilog::RegisterBackend(&m_LoggingBackend); // initialize and start navigation data recorder form xml recording m_NavigationDataRecorder->StartRecording(); m_IsExperimentRunning = true; m_ImageAndNavigationDataLoggingTimer->start(1000); } } } void QmitkUSNavigationMarkerPlacement::OnFinishExperiment() { this->WaitCursorOn(); MITK_INFO("USNavigationLogging") << "Experiment finished!"; MITK_INFO("USNavigationLogging") << "Position/Orientation of needle tip: " << (dynamic_cast( m_CombinedModality->GetTrackingDeviceDataSource()->GetOutput(0))) ->GetPosition(); MITK_INFO("USNavigationLogging") << "Position of target: " << m_TargetNodeDisplacementFilter->GetRawDisplacementNavigationData(0)->GetPosition(); MITK_INFO("USNavigationLogging") << "Total duration: " << m_NavigationStepTimer->GetTotalDuration(); m_ImageAndNavigationDataLoggingTimer->stop(); ui->runningLabel->setPixmap(m_IconNotRunning); m_NavigationStepTimer->Stop(); ui->finishExperimentButton->setDisabled(true); ui->startExperimentButton->setEnabled(true); MITK_INFO("USNavigationLogging") << "Writing logging data to " << m_ExperimentResultsSubDirectory.toStdString(); // save ultrasound images to the file system QDir(m_ExperimentResultsSubDirectory).mkdir("ImageStream"); m_USImageLoggingFilter->Update(); m_USImageLoggingFilter->SetImageFilesExtension(".jpg"); m_USImageLoggingFilter->SaveImages( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "ImageStream" + QDir::separator()).toStdString()); m_USImageLoggingFilter = mitk::USImageLoggingFilter::New(); m_NavigationDataRecorder->StopRecording(); // Write data to csv and xml file mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.xml").toStdString().c_str())); mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.csv").toStdString().c_str())); // write logged navigation data messages to separate file std::stringstream csvNavigationMessagesFilename; csvNavigationMessagesFilename << m_ExperimentResultsSubDirectory.toStdString() << QDir::separator().toLatin1() << "CSVNavigationMessagesLogFile.csv"; MITK_INFO("USNavigationLogging") << "Writing logged navigation messages to separate csv file: " << csvNavigationMessagesFilename.str(); m_LoggingBackend.WriteCSVFileWithNavigationMessages(csvNavigationMessagesFilename.str()); mbilog::UnregisterBackend(&m_LoggingBackend); m_IsExperimentRunning = false; m_ImageAndNavigationDataLoggingTimer->stop(); m_CombinedModality = nullptr; // reset scene number for next experiment m_SceneNumber = 1; this->WaitCursorOff(); MITK_INFO("USNavigationLogging") << "Finished!"; } void QmitkUSNavigationMarkerPlacement::OnSettingsChanged(itk::SmartPointer settings) { // initialize gui according to the experiment mode setting bool experimentMode = false; settings->GetBoolProperty("settings.experiment-mode", experimentMode); ui->startExperimentButton->setVisible(experimentMode); ui->finishExperimentButton->setVisible(experimentMode); ui->runningLabel->setVisible(experimentMode); if (experimentMode && !m_IsExperimentRunning) { ui->runningLabel->setPixmap(m_IconNotRunning); } else if (!experimentMode) { if (m_IsExperimentRunning) { this->OnFinishExperiment(); } } // get the results directory from the settings and use home directory if // there is no results directory configured std::string resultsDirectory; if (settings->GetStringProperty("settings.experiment-results-directory", resultsDirectory)) { m_ResultsDirectory = QString::fromStdString(resultsDirectory); } else { m_ResultsDirectory = QDir::homePath(); } // make sure that the results directory exists QDir resultsDirectoryQDir = QDir(m_ResultsDirectory); if (!resultsDirectoryQDir.exists()) { resultsDirectoryQDir.mkpath(m_ResultsDirectory); } MITK_INFO("USNavigation") << "Results Directory: " << m_ResultsDirectory.toStdString(); } void QmitkUSNavigationMarkerPlacement::ReinitOnImage() { if (!m_ReinitAlreadyDone && m_CombinedModality.IsNotNull()) { // make sure that the output is already calibrated correctly // (if the zoom level was changed recently) m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); if (image.IsNotNull() && image->IsInitialized()) { // make a reinit on the ultrasound image - mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); - if (renderWindow != nullptr && image->GetTimeGeometry()->IsValid()) + mitk::IRenderWindowPart *renderWindowPart = this->GetRenderWindowPart(); + if (renderWindowPart != nullptr && image->GetTimeGeometry()->IsValid()) { - renderWindow->GetRenderingManager()->InitializeViews( + renderWindowPart->GetRenderingManager()->InitializeViews( image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - renderWindow->GetRenderingManager()->RequestUpdateAll(); + renderWindowPart->GetRenderingManager()->RequestUpdateAll(); } this->RequestRenderWindowUpdate(); m_ReinitAlreadyDone = true; } } } void QmitkUSNavigationMarkerPlacement::Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); ++it) { if (it->Value()->GetData() && strcmp(it->Value()->GetData()->GetNameOfClass(), "Image") == 0) { // convert image to 3d image if it is 2d at the moment mitk::Image::Pointer image = dynamic_cast(it->Value()->GetData()); if (image.IsNotNull() && image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { mitk::Convert2Dto3DImageFilter::Pointer convert2DTo3DImageFilter = mitk::Convert2Dto3DImageFilter::New(); convert2DTo3DImageFilter->SetInput(image); convert2DTo3DImageFilter->Update(); it->Value()->SetData(convert2DTo3DImageFilter->GetOutput()); } } } } void QmitkUSNavigationMarkerPlacement::CreateOverlays() { // initialize warning overlay (and do not display it, yet) m_WarnOverlay->SetText("Warning: No calibration available for current depth."); // set position and font size for the text overlay // (nonesense postition as a layouter is used, but it ignored // the overlay without setting a position here) mitk::Point2D overlayPosition; overlayPosition.SetElement(0, -50.0f); overlayPosition.SetElement(1, -50.0f); m_WarnOverlay->SetPosition2D(overlayPosition); m_WarnOverlay->SetFontSize(22); m_WarnOverlay->SetColor(1, 0, 0); // overlay should be red } void QmitkUSNavigationMarkerPlacement::UpdateToolStorage() { if (m_NavigationDataSource.IsNull()) { m_NavigationDataSource = m_CombinedModality->GetNavigationDataSource(); } if (m_NavigationDataSource.IsNull()) { MITK_WARN << "Found an invalid navigation data source object!"; } us::ModuleContext *context = us::GetModuleContext(); std::string id = m_NavigationDataSource->US_PROPKEY_ID; std::string filter = "(" + mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; // Get Storage std::vector> refs = context->GetServiceReferences(); m_CurrentStorage = context->GetService(refs.front()); if (m_CurrentStorage.IsNull()) { MITK_WARN << "Found an invalid storage object!"; } else if (m_CurrentStorage->GetToolCount() != m_NavigationDataSource->GetNumberOfOutputs()) // there is something wrong with the storage { MITK_WARN << "Found a tool storage, but it has not the same number of tools like the NavigationDataSource. This " "storage won't be used because it isn't the right one."; m_CurrentStorage = nullptr; } } diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp index 9d4ecc48dd..005bab3301 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp @@ -1,731 +1,732 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIGTTrackingLabView.h" +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include #include #include // vtk #include const std::string QmitkIGTTrackingLabView::VIEW_ID = "org.mitk.views.igttrackinglab"; QmitkIGTTrackingLabView::QmitkIGTTrackingLabView() : QmitkAbstractView() ,m_Source(nullptr) ,m_PermanentRegistrationFilter(nullptr) ,m_Visualizer(nullptr) ,m_VirtualView(nullptr) ,m_PSRecordingPointSet(nullptr) ,m_PointSetRecording(false) ,m_PermanentRegistration(false) ,m_CameraView(false) ,m_ImageFiducialsDataNode(nullptr) ,m_TrackerFiducialsDataNode(nullptr) ,m_PermanentRegistrationSourcePoints(nullptr) { } //############################################################################################### //############################################################################################### //############################## Timer method for IGT pipeline updating ######################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::UpdateTimer() { if (m_PermanentRegistration && m_PermanentRegistrationFilter.IsNotNull()) { if(IsTransformDifferenceHigh(m_ObjectmarkerNavigationData, m_ObjectmarkerNavigationDataLastUpdate)) { m_ObjectmarkerNavigationDataLastUpdate->Graft(m_ObjectmarkerNavigationData); m_PermanentRegistrationFilter->Update(); } } if (m_CameraView && m_VirtualView.IsNotNull()) {m_VirtualView->Update();} if(m_PointSetRecording && m_PSRecordingPointSet.IsNotNull()) { int size = m_PSRecordingPointSet->GetSize(); mitk::NavigationData::Pointer nd = m_PointSetRecordingNavigationData; if(size > 0) { mitk::Point3D p = m_PSRecordingPointSet->GetPoint(size-1); if(p.EuclideanDistanceTo(nd->GetPosition()) > (double) m_Controls.m_PSRecordingSpinBox->value()) m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); } else m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); } } //############################################################################################### //############################################################################################### //############################## Slots of CONFIGURATION step #################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnSetupNavigation() { if(m_Source.IsNotNull()) if(m_Source->IsTracking()) return; mitk::DataStorage* ds = this->GetDataStorage(); if(ds == nullptr) { MITK_WARN << "IGTSurfaceTracker: Error. Cannot access DataStorage. Navigation not possible"; return; } //Building up the filter pipeline try { this->InitializeRegistration(); } catch(mitk::IGTException& e) { MITK_WARN << "Error while building the IGT-Pipeline: " << e.GetDescription(); this->DestroyIGTPipeline(); // destroy the pipeline if building is incomplete return; } catch(...) { MITK_WARN << "Unexpected error while building the IGT-Pipeline"; this->DestroyIGTPipeline(); return; } } void QmitkIGTTrackingLabView::OnInstrumentSelected() { if (m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource().IsNotNull()) { m_InstrumentNavigationData = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID()); } else { m_Controls.m_PointerNameLabel->setText(""); return; } if (m_InstrumentNavigationData.IsNotNull()) { m_Controls.m_PointerNameLabel->setText(m_InstrumentNavigationData->GetName()); } else { m_Controls.m_PointerNameLabel->setText(""); } } void QmitkIGTTrackingLabView::OnObjectmarkerSelected() { if (m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource().IsNotNull()) { m_ObjectmarkerNavigationData = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID()); MITK_INFO << "Objectmarker rotation: " << m_ObjectmarkerNavigationData->GetOrientation(); } else { m_Controls.m_ObjectmarkerNameLabel->setText(""); return; } if (m_ObjectmarkerNavigationData.IsNotNull()) { m_Controls.m_ObjectmarkerNameLabel->setText(m_ObjectmarkerNavigationData->GetName()); } else { m_Controls.m_ObjectmarkerNameLabel->setText(""); } } //############################################################################################### //############################################################################################### //####################### Slots of INITIAL REGISTRATION step #################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnInitialRegistration() { //Check for initialization if (!CheckRegistrationInitialization()) return; mitk::PointSet::Pointer imageFiducials = dynamic_cast(m_ImageFiducialsDataNode->GetData()); mitk::PointSet::Pointer trackerFiducials = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); //############### conversion to vtk data types (we will use the vtk landmark based transform) ########################## //convert point sets to vtk poly data vtkSmartPointer sourcePoints = vtkSmartPointer::New(); vtkSmartPointer targetPoints = vtkSmartPointer::New(); for (int i=0; iGetSize(); i++) { double point[3] = {imageFiducials->GetPoint(i)[0],imageFiducials->GetPoint(i)[1],imageFiducials->GetPoint(i)[2]}; sourcePoints->InsertNextPoint(point); double point_targets[3] = {trackerFiducials->GetPoint(i)[0],trackerFiducials->GetPoint(i)[1],trackerFiducials->GetPoint(i)[2]}; targetPoints->InsertNextPoint(point_targets); } //########################### here, the actual transform is computed ########################## //compute transform vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(sourcePoints); transform->SetTargetLandmarks(targetPoints); transform->SetModeToRigidBody(); transform->Modified(); transform->Update(); //compute FRE of transform double FRE = mitk::StaticIGTHelperFunctions::ComputeFRE(imageFiducials, trackerFiducials, transform); m_Controls.m_RegistrationWidget->SetQualityDisplayText("FRE: " + QString::number(FRE) + " mm"); //############################################################################################# //############### conversion back to itk/mitk data types ########################## //convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); itk::Matrix rotationDouble = itk::Matrix(); itk::Vector translationDouble = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); for(int k=0; k<3; k++) for(int l=0; l<3; l++) { rotationFloat[k][l] = m->GetElement(k,l); rotationDouble[k][l] = m->GetElement(k,l); } for(int k=0; k<3; k++) { translationFloat[k] = m->GetElement(k,3); translationDouble[k] = m->GetElement(k,3); } //create affine transform 3D surface mitk::AffineTransform3D::Pointer mitkTransform = mitk::AffineTransform3D::New(); mitkTransform->SetMatrix(rotationDouble); mitkTransform->SetOffset(translationDouble); //############################################################################################# //############### object is transformed ########################## //save transform m_T_ObjectReg = mitk::NavigationData::New(mitkTransform); // this is stored in a member because it is needed for permanent registration later on //transform surface if(m_Controls.m_SurfaceActive->isChecked() && m_Controls.m_ObjectComboBox->GetSelectedNode().IsNotNull()) { m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(mitkTransform); } //################################################################ //############### if activated: ct image is also transformed ########################## //transform ct image //todo: Explain that AffineTransform3D is used, because NavigationData does not support spacing! if(m_Controls.m_ImageActive->isChecked() && m_Controls.m_ImageComboBox->GetSelectedNode().IsNotNull()) { //first we have to store the original ct image transform to compose it with the new transform later mitk::AffineTransform3D::Pointer imageTransform = m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); m_T_ImageGeo = mitk::AffineTransform3D::New(); // this is also stored in a member because it is needed for permanent registration later on //now the new transform of the ct image is computed m_T_ImageGeo->Compose(imageTransform); imageTransform->Compose(mitkTransform); mitk::AffineTransform3D::Pointer newImageTransform = mitk::AffineTransform3D::New(); //create new image transform... setting the composed directly leads to an error itk::Matrix rotationFloatNew = imageTransform->GetMatrix(); itk::Vector translationFloatNew = imageTransform->GetOffset(); newImageTransform->SetMatrix(rotationFloatNew); newImageTransform->SetOffset(translationFloatNew); m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(newImageTransform); m_T_ImageReg = m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); } //################################################################ } void QmitkIGTTrackingLabView::OnAddRegistrationTrackingFiducial() { mitk::NavigationData::Pointer nd = m_InstrumentNavigationData; if( nd.IsNull() || !nd->IsDataValid()) { QMessageBox::warning( nullptr, "Invalid tracking data", "Navigation data is not available or invalid!", QMessageBox::Ok ); return; } if(m_TrackerFiducialsDataNode.IsNotNull() && m_TrackerFiducialsDataNode->GetData() != nullptr) { mitk::PointSet::Pointer ps = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); ps->InsertPoint(ps->GetSize(), nd->GetPosition()); } else QMessageBox::warning(nullptr, "IGTSurfaceTracker: Error", "Can not access Tracker Fiducials. Adding fiducial not possible!"); } void QmitkIGTTrackingLabView::InitializeRegistration() { mitk::DataStorage* ds = this->GetDataStorage(); if( ds == nullptr ) return; // let the registration widget know about the slice navigation controllers // in the active render window part (crosshair updates) foreach(QmitkRenderWindow* renderWindow, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { m_Controls.m_RegistrationWidget->AddSliceNavigationController(renderWindow->GetSliceNavigationController()); } if(m_ImageFiducialsDataNode.IsNull()) { m_ImageFiducialsDataNode = mitk::DataNode::New(); mitk::PointSet::Pointer ifPS = mitk::PointSet::New(); m_ImageFiducialsDataNode->SetData(ifPS); mitk::Color color; color.Set(1.0f, 0.0f, 0.0f); m_ImageFiducialsDataNode->SetName("Image Fiducials"); m_ImageFiducialsDataNode->SetColor(color); m_ImageFiducialsDataNode->SetBoolProperty( "updateDataOnRender", false ); ds->Add(m_ImageFiducialsDataNode); } m_Controls.m_RegistrationWidget->SetImageFiducialsNode(m_ImageFiducialsDataNode); if(m_TrackerFiducialsDataNode.IsNull()) { m_TrackerFiducialsDataNode = mitk::DataNode::New(); mitk::PointSet::Pointer tfPS = mitk::PointSet::New(); m_TrackerFiducialsDataNode->SetData(tfPS); mitk::Color color; color.Set(0.0f, 1.0f, 0.0f); m_TrackerFiducialsDataNode->SetName("Tracking Fiducials"); m_TrackerFiducialsDataNode->SetColor(color); m_TrackerFiducialsDataNode->SetBoolProperty( "updateDataOnRender", false ); ds->Add(m_TrackerFiducialsDataNode); } m_Controls.m_RegistrationWidget->SetTrackerFiducialsNode(m_TrackerFiducialsDataNode); } //############################################################################################### //############################################################################################### //####################### Slots of PERMANENT REGISTRATION step ################################## //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnPermanentRegistration(bool on) { if(on) { //###################################################################### //######################## inititalization ############################# //###################################################################### //some initial checks if(!CheckRegistrationInitialization()) { m_Controls.m_UsePermanentRegistrationToggle->setChecked(false); return; } //remember initial object transform to calculate the object to marker transform later on and convert it to navigation data mitk::AffineTransform3D::Pointer transform = this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); mitk::NavigationData::Pointer T_Object = mitk::NavigationData::New(transform,false); //TODO: catch exception during conversion? //then reset the transform because we will now start to calculate the permanent registration this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIdentity(); if(m_Controls.m_ImageActive->isChecked()) {this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ImageGeo);} //create the permanent registration filter m_PermanentRegistrationFilter = mitk::NavigationDataObjectVisualizationFilter::New(); //###################################################################### //first: initialize permanent registration of surface (always activated) //###################################################################### //connect filter to source m_PermanentRegistrationFilter->SetInput(0,this->m_ObjectmarkerNavigationData); //set representation object m_PermanentRegistrationFilter->SetRepresentationObject(0,this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()); //get the marker transform out of the navigation data mitk::NavigationData::Pointer T_Marker = m_ObjectmarkerNavigationData; //compute transform from object to marker (T_MarkerRel = T_Object * T_Marker^-1) mitk::NavigationData::Pointer T_MarkerRel = mitk::NavigationData::New(); T_MarkerRel->Compose(T_Object); T_MarkerRel->Compose(T_Marker->GetInverse()); m_T_MarkerRel = T_MarkerRel; m_PermanentRegistrationFilter->SetOffset(0,m_T_MarkerRel->GetAffineTransform3D()); //###################################################################### //second: initialize permanent registration of image (if activated) //###################################################################### if (m_Controls.m_ImageActive->isChecked() && (m_Controls.m_ImageComboBox->GetSelectedNode().IsNotNull())) { mitk::DataNode::Pointer imageNode = this->m_Controls.m_ImageComboBox->GetSelectedNode(); imageNode->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_LINEAR) ); m_PermanentRegistrationFilter->SetInput(1,this->m_ObjectmarkerNavigationData); m_PermanentRegistrationFilter->SetRepresentationObject(1,imageNode->GetData()); //for the image we can't use NavigationData objects as transforms because an image needs additional geometry information, e.g., spacing //thus we use mitk::AffineTransform3D objects //computer transform from image to marker (T_ImageRel = T_ImageGeo * T_MarkerRel) mitk::AffineTransform3D::Pointer T_ImageRel = mitk::AffineTransform3D::New(); T_ImageRel->SetIdentity(); T_ImageRel->Compose(m_T_ImageGeo); T_ImageRel->Compose(m_T_MarkerRel->GetAffineTransform3D()); m_PermanentRegistrationFilter->SetOffset(1,T_ImageRel); } //some general stuff m_PermanentRegistration = true; m_ObjectmarkerNavigationDataLastUpdate = mitk::NavigationData::New(); } else //if off = disable the permanent registration { //stop permanent registration m_PermanentRegistration = false; //restore old registration if(m_T_ObjectReg.IsNotNull()) {this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ObjectReg->GetAffineTransform3D());} if(m_T_ImageReg.IsNotNull()) {this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ImageReg);} //delete filter m_PermanentRegistrationFilter = nullptr; } } //############################################################################################### //############################################################################################### //####################### Slots of POINT SET RECORDING step ##################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnPointSetRecording(bool record) { mitk::DataStorage* ds = this->GetDataStorage(); if(record) { if (m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedToolID() == -1) { QMessageBox::warning(nullptr, "Error", "No tool selected for point set recording!"); m_Controls.m_PointSetRecordCheckBox->setChecked(false); return; } m_PointSetRecordingNavigationData = m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedToolID()); //initialize point set mitk::DataNode::Pointer psRecND = ds->GetNamedNode("Recorded Points"); if(m_PSRecordingPointSet.IsNull() || psRecND.IsNull()) { m_PSRecordingPointSet = nullptr; m_PSRecordingPointSet = mitk::PointSet::New(); mitk::DataNode::Pointer dn = mitk::DataNode::New(); dn->SetName("Recorded Points"); dn->SetColor(0.,1.,0.); dn->SetData(m_PSRecordingPointSet); ds->Add(dn); } else { m_PSRecordingPointSet->Clear(); } m_PointSetRecording = true; } else { m_PointSetRecording = false; } } //############################################################################################### //############################################################################################### //####################### Slots of VIRTUAL CAMERA VIEW step ##################################### //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::OnVirtualCamera(bool on) { if (m_Controls.m_CameraViewSelection->GetSelectedToolID() == -1) { m_Controls.m_ActivateNeedleView->setChecked(false); QMessageBox::warning(nullptr, "Error", "No tool selected for camera view!"); return; } if(on) { m_VirtualView = mitk::CameraVisualization::New(); m_VirtualView->SetInput(m_Controls.m_CameraViewSelection->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_CameraViewSelection->GetSelectedToolID())); mitk::Vector3D viewDirection; viewDirection[0] = (int)(m_Controls.m_NeedleViewX->isChecked()); viewDirection[1] = (int)(m_Controls.m_NeedleViewY->isChecked()); viewDirection[2] = (int)(m_Controls.m_NeedleViewZ->isChecked()); if (m_Controls.m_NeedleViewInvert->isChecked()) viewDirection *= -1; m_VirtualView->SetDirectionOfProjectionInToolCoordinates(viewDirection); mitk::Vector3D viewUpVector; viewUpVector[0] = (int)(m_Controls.m_NeedleUpX->isChecked()); viewUpVector[1] = (int)(m_Controls.m_NeedleUpY->isChecked()); viewUpVector[2] = (int)(m_Controls.m_NeedleUpZ->isChecked()); if (m_Controls.m_NeedleUpInvert->isChecked()) viewUpVector *= -1; m_VirtualView->SetViewUpInToolCoordinates(viewUpVector); m_VirtualView->SetRenderer(this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()); //next line: better code when this plugin is migrated to mitk::abstractview //m_VirtualView->SetRenderer(mitk::BaseRenderer::GetInstance(this->GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow())); m_CameraView = true; //make pointer itself invisible m_Controls.m_CameraViewSelection->GetSelectedNavigationTool()->GetDataNode()->SetBoolProperty("visible",false); //disable UI elements m_Controls.m_ViewDirectionBox->setEnabled(false); m_Controls.m_ViewUpBox->setEnabled(false); } else { m_VirtualView = nullptr; m_CameraView = false; m_Controls.m_CameraViewSelection->GetSelectedNavigationTool()->GetDataNode()->SetBoolProperty("visible",true); m_Controls.m_ViewDirectionBox->setEnabled(true); m_Controls.m_ViewUpBox->setEnabled(true); } } //############################################################################################### //############################################################################################### //############################## some general UI methods, always needed ######################### //############################################################################################### //############################################################################################### QmitkIGTTrackingLabView::~QmitkIGTTrackingLabView() { if (m_Timer->isActive()) m_Timer->stop(); } void QmitkIGTTrackingLabView::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); this->CreateBundleWidgets(); this->CreateConnections(); } void QmitkIGTTrackingLabView::CreateBundleWidgets() { //initialize registration widget m_Controls.m_RegistrationWidget->HideStaticRegistrationRadioButton(true); m_Controls.m_RegistrationWidget->HideContinousRegistrationRadioButton(true); m_Controls.m_RegistrationWidget->HideUseICPRegistrationCheckbox(true); } void QmitkIGTTrackingLabView::CreateConnections() { //initialize timer m_Timer = new QTimer(this); //create connections connect(m_Timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); connect( m_Controls.m_UsePermanentRegistrationToggle, SIGNAL(toggled(bool)), this, SLOT(OnPermanentRegistration(bool)) ); connect( m_Controls.m_TrackingDeviceSelectionWidget, SIGNAL(NavigationDataSourceSelected(mitk::NavigationDataSource::Pointer)), this, SLOT(OnSetupNavigation()) ); connect( m_Controls.m_UseAsPointerButton, SIGNAL(clicked()), this, SLOT(OnInstrumentSelected()) ); connect( m_Controls.m_UseAsObjectmarkerButton, SIGNAL(clicked()), this, SLOT(OnObjectmarkerSelected()) ); connect( m_Controls.m_RegistrationWidget, SIGNAL(AddedTrackingFiducial()), this, SLOT(OnAddRegistrationTrackingFiducial()) ); connect( m_Controls.m_RegistrationWidget, SIGNAL(PerformFiducialRegistration()), this, SLOT(OnInitialRegistration()) ); connect( m_Controls.m_PointSetRecordCheckBox, SIGNAL(toggled(bool)), this, SLOT(OnPointSetRecording(bool)) ); connect( m_Controls.m_ActivateNeedleView, SIGNAL(toggled(bool)), this, SLOT(OnVirtualCamera(bool)) ); //start timer m_Timer->start(30); //initialize Combo Boxes m_Controls.m_ObjectComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ObjectComboBox->SetAutoSelectNewItems(false); m_Controls.m_ObjectComboBox->SetPredicate(mitk::NodePredicateDataType::New("Surface")); m_Controls.m_ImageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ImageComboBox->SetAutoSelectNewItems(false); m_Controls.m_ImageComboBox->SetPredicate(mitk::NodePredicateDataType::New("Image")); } void QmitkIGTTrackingLabView::SetFocus() { m_Controls.m_UseAsPointerButton->setFocus(); } //############################################################################################### //############################################################################################### //####################### some additional slots and help methods ################################ //####################### for cleaner code - not that important ################################ //####################### to understand the basic functions ################################ //############################################################################################### //############################################################################################### void QmitkIGTTrackingLabView::DestroyIGTPipeline() { if(m_Source.IsNotNull()) { m_Source->StopTracking(); m_Source->Disconnect(); m_Source = nullptr; } m_PermanentRegistrationFilter = nullptr; m_Visualizer = nullptr; m_VirtualView = nullptr; } bool QmitkIGTTrackingLabView::CheckRegistrationInitialization() { // a couple of variables which we need in this method std::string warningMessage = ""; bool initializationErrorDetected = false; mitk::PointSet::Pointer imageFiducials,trackerFiducials; // check some initialization stuff if (m_ImageFiducialsDataNode.IsNull() || m_TrackerFiducialsDataNode.IsNull()) { warningMessage = "Initialization not finished!"; MITK_WARN << warningMessage; QMessageBox::warning(nullptr, "Registration not possible", warningMessage.c_str()); return false; } else { imageFiducials = dynamic_cast(m_ImageFiducialsDataNode->GetData()); trackerFiducials = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); } // now, do a lot of other checks... if (m_Controls.m_SurfaceActive->isChecked() && m_Controls.m_ObjectComboBox->GetSelectedNode().IsNull()) { warningMessage = "No surface selected for registration.\nRegistration is not possible"; initializationErrorDetected = true; } else if (m_Controls.m_ImageActive->isChecked() && m_Controls.m_ImageComboBox->GetSelectedNode().IsNull()) { warningMessage = "No image selected for registration.\nRegistration is not possible"; initializationErrorDetected = true; } else if (imageFiducials.IsNull() || trackerFiducials.IsNull()) { warningMessage = "Fiducial data objects not found. \n" "Please set 3 or more fiducials in the image and with the tracking system.\n\n" "Registration is not possible"; initializationErrorDetected = true; } else if ((imageFiducials->GetSize() < 3) || (trackerFiducials->GetSize() < 3) || (imageFiducials->GetSize() != trackerFiducials->GetSize())) { warningMessage = "Not enough fiducial pairs found. At least 3 fiducial must exist for the image and the tracking system respectively."; initializationErrorDetected = true; } // finaly: if an err was detected, give a warning and an error popup, then return false if(initializationErrorDetected) { MITK_WARN << warningMessage; QMessageBox::warning(nullptr, "Registration not possible", warningMessage.c_str()); return false; } //if no error was detected simply return true else {return true;} } bool QmitkIGTTrackingLabView::IsTransformDifferenceHigh(mitk::NavigationData::Pointer transformA, mitk::NavigationData::Pointer transformB, double euclideanDistanceThreshold, double angularDifferenceThreshold) { if(transformA.IsNull() || transformA.IsNull()) {return false;} mitk::Point3D posA,posB; posA = transformA->GetPosition(); posB = transformB->GetPosition(); if(posA.EuclideanDistanceTo(posB) > euclideanDistanceThreshold) {return true;} double returnValue; mitk::Quaternion rotA,rotB; rotA = transformA->GetOrientation(); rotB = transformB->GetOrientation(); itk::Vector point; //caution 5D-Tools: Vector must lie in the YZ-plane for a correct result. point[0] = 0.0; point[1] = 0.0; point[2] = 100000.0; rotA.normalize(); rotB.normalize(); itk::Matrix rotMatrixA; for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixA[i][j] = rotA.rotation_matrix_transpose().transpose()[i][j]; itk::Matrix rotMatrixB; for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixB[i][j] = rotB.rotation_matrix_transpose().transpose()[i][j]; itk::Vector pt1 = rotMatrixA * point; itk::Vector pt2 = rotMatrixB * point; returnValue = (pt1[0]*pt2[0]+pt1[1]*pt2[1]+pt1[2]*pt2[2]) / ( sqrt(pow(pt1[0],2.0)+pow(pt1[1],2.0)+pow(pt1[2],2.0)) * sqrt(pow(pt2[0],2.0)+pow(pt2[1],2.0)+pow(pt2[2],2.0))); returnValue = acos(returnValue); if(returnValue*57.3 > angularDifferenceThreshold){return true;} return false; } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp index d32826c240..62c5c49005 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistration.cpp @@ -1,104 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include //Mitk #include #include #include #include #include #include #include // Qmitk #include "QmitkIGTFiducialRegistration.h" +#include // Qt #include #include #include // MicroServices #include #include #include "usServiceReference.h" const std::string QmitkIGTFiducialRegistration::VIEW_ID = "org.mitk.views.IGTFiducialRegistration"; void QmitkIGTFiducialRegistration::SetFocus() { } void QmitkIGTFiducialRegistration::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); //Connect signals and slots connect(m_Controls.m_ChooseSelectedPointer, SIGNAL(clicked()), this, SLOT(PointerSelectionChanged())); connect(m_Controls.m_ChooseSelectedImage, SIGNAL(clicked()), this, SLOT(ImageSelectionChanged())); //Initialize Combobox m_Controls.m_DataStorageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_DataStorageComboBox->SetAutoSelectNewItems(false); m_Controls.m_DataStorageComboBox->SetPredicate(mitk::NodePredicateOr::New(mitk::NodePredicateDataType::New("Surface"), mitk::NodePredicateDataType::New("Image"))); //Initialize Fiducial Registration Widget m_Controls.m_FiducialRegistrationWidget->setDataStorage(this->GetDataStorage()); m_Controls.m_FiducialRegistrationWidget->HideStaticRegistrationRadioButton(true); m_Controls.m_FiducialRegistrationWidget->HideContinousRegistrationRadioButton(true); m_Controls.m_FiducialRegistrationWidget->HideUseICPRegistrationCheckbox(true); } void QmitkIGTFiducialRegistration::InitializeRegistration() { foreach(QmitkRenderWindow* renderWindow, this->GetRenderWindowPart()->GetQmitkRenderWindows().values()) { this->m_Controls.m_FiducialRegistrationWidget->AddSliceNavigationController(renderWindow->GetSliceNavigationController()); } } void QmitkIGTFiducialRegistration::PointerSelectionChanged() { InitializeRegistration(); int toolID = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID(); m_TrackingPointer = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(toolID); m_Controls.m_FiducialRegistrationWidget->setTrackerNavigationData(m_TrackingPointer); m_Controls.m_PointerLabel->setText(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationTool()->GetToolName().c_str()); } void QmitkIGTFiducialRegistration::ImageSelectionChanged() { InitializeRegistration(); m_Controls.m_ImageLabel->setText(m_Controls.m_DataStorageComboBox->GetSelectedNode()->GetName().c_str()); m_Controls.m_FiducialRegistrationWidget->setImageNode(m_Controls.m_DataStorageComboBox->GetSelectedNode()); } QmitkIGTFiducialRegistration::QmitkIGTFiducialRegistration() { } QmitkIGTFiducialRegistration::~QmitkIGTFiducialRegistration() { } diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake index fce4919a70..6fc8f9b490 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake @@ -1,37 +1,36 @@ set(SRC_CPP_FILES QmitkMxNMultiWidgetEditor.cpp - QmitkMultiWidgetDecorationManager.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkMxNMultiWidgetEditorPreferencePage.cpp ) set(UI_FILES src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui ) set(MOC_H_FILES src/QmitkMxNMultiWidgetEditor.h src/internal/mitkPluginActivator.h src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h ) set(CACHED_RESOURCE_FILES resources/MxNMultiWidgetEditor.svg plugin.xml ) set(QRC_FILES resources/QmitkMxNMultiWidgetEditor.qrc ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp index 79ae91af09..63b2e44dfb 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp @@ -1,272 +1,185 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMxNMultiWidgetEditor.h" #include #include #include #include #include // mxn multi widget editor plugin #include "QmitkMultiWidgetDecorationManager.h" // mitk qt widgets module #include #include #include +// qt +#include + const QString QmitkMxNMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.mxnmultiwidget"; -class QmitkMxNMultiWidgetEditor::Impl final +struct QmitkMxNMultiWidgetEditor::Impl final { - -public: - Impl(); ~Impl() = default; - QmitkMxNMultiWidget* m_MxNMultiWidget; QmitkInteractionSchemeToolBar* m_InteractionSchemeToolBar; QmitkMultiWidgetConfigurationToolBar* m_ConfigurationToolBar; - - std::unique_ptr m_MultiWidgetDecorationManager; }; QmitkMxNMultiWidgetEditor::Impl::Impl() - : m_MxNMultiWidget(nullptr) - , m_InteractionSchemeToolBar(nullptr) + : m_InteractionSchemeToolBar(nullptr) , m_ConfigurationToolBar(nullptr) { // nothing here } ////////////////////////////////////////////////////////////////////////// // QmitkMxNMultiWidgetEditor ////////////////////////////////////////////////////////////////////////// QmitkMxNMultiWidgetEditor::QmitkMxNMultiWidgetEditor() - : m_Impl(new Impl()) -{} - -QmitkMxNMultiWidgetEditor::~QmitkMxNMultiWidgetEditor() -{ - GetSite()->GetPage()->RemovePartListener(this); -} - -QmitkRenderWindow* QmitkMxNMultiWidgetEditor::GetActiveQmitkRenderWindow() const -{ - if (nullptr != m_Impl->m_MxNMultiWidget) - { - auto activeRenderWindowWidget = m_Impl->m_MxNMultiWidget->GetActiveRenderWindowWidget(); - if (nullptr != activeRenderWindowWidget) - { - return activeRenderWindowWidget->GetRenderWindow(); - } - } - - return nullptr; -} - -QHash QmitkMxNMultiWidgetEditor::GetQmitkRenderWindows() const -{ - QHash result; - if (nullptr == m_Impl->m_MxNMultiWidget) - { - return result; - } - - result = m_Impl->m_MxNMultiWidget->GetRenderWindows(); - return result; -} - -QmitkRenderWindow* QmitkMxNMultiWidgetEditor::GetQmitkRenderWindow(const QString& id) const + : QmitkAbstractMultiWidgetEditor() + , m_Impl(std::make_unique()) { - if (nullptr == m_Impl->m_MxNMultiWidget) - { - return nullptr; - } - - return m_Impl->m_MxNMultiWidget->GetRenderWindow(id); -} - -mitk::Point3D QmitkMxNMultiWidgetEditor::GetSelectedPosition(const QString& id) const -{ - if (nullptr == m_Impl->m_MxNMultiWidget) - { - return mitk::Point3D(); - } - - return m_Impl->m_MxNMultiWidget->GetSelectedPosition(id); -} - -void QmitkMxNMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D& pos, const QString& id) -{ - if (nullptr != m_Impl->m_MxNMultiWidget) - { - m_Impl->m_MxNMultiWidget->SetSelectedPosition(id, pos); - } -} - -void QmitkMxNMultiWidgetEditor::EnableDecorations(bool enable, const QStringList& decorations) -{ - m_Impl->m_MultiWidgetDecorationManager->ShowDecorations(enable, decorations); -} - -bool QmitkMxNMultiWidgetEditor::IsDecorationEnabled(const QString& decoration) const -{ - return m_Impl->m_MultiWidgetDecorationManager->IsDecorationVisible(decoration); -} - -QStringList QmitkMxNMultiWidgetEditor::GetDecorations() const -{ - return m_Impl->m_MultiWidgetDecorationManager->GetDecorations(); + // nothing here } -berry::IPartListener::Events::Types QmitkMxNMultiWidgetEditor::GetPartEventTypes() const +QmitkMxNMultiWidgetEditor::~QmitkMxNMultiWidgetEditor() { - return Events::CLOSED | Events::OPENED; + GetSite()->GetPage()->RemovePartListener(this); } -void QmitkMxNMultiWidgetEditor::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) +void QmitkMxNMultiWidgetEditor::OnLayoutSet(int row, int column) { - if (partRef->GetId() == QmitkMxNMultiWidgetEditor::EDITOR_ID) + const auto &multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr != multiWidget) { - m_Impl->m_MxNMultiWidget->ActivateAllCrosshairs(true); + multiWidget->SetCrosshairVisibility(true); + QmitkAbstractMultiWidgetEditor::OnLayoutSet(row, column); } } -void QmitkMxNMultiWidgetEditor::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) +void QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { - if (partRef->GetId() == QmitkMxNMultiWidgetEditor::EDITOR_ID) + const auto &multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) { - m_Impl->m_MxNMultiWidget->ActivateAllCrosshairs(false); + return; } -} - -QmitkMxNMultiWidget* QmitkMxNMultiWidgetEditor::GetMxNMultiWidget() -{ - return m_Impl->m_MxNMultiWidget; -} -void QmitkMxNMultiWidgetEditor::OnLayoutSet(int row, int column) -{ - m_Impl->m_MxNMultiWidget->ResetLayout(row, column); - m_Impl->m_MxNMultiWidget->ActivateAllCrosshairs(true); - FirePropertyChange(berry::IWorkbenchPartConstants::PROP_INPUT); -} - -void QmitkMxNMultiWidgetEditor::OnSynchronize(bool synchronized) -{ - m_Impl->m_MxNMultiWidget->Synchronize(synchronized); -} - -void QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) -{ if (mitk::InteractionSchemeSwitcher::PACSStandard == scheme) { m_Impl->m_InteractionSchemeToolBar->setVisible(true); } else { m_Impl->m_InteractionSchemeToolBar->setVisible(false); } - m_Impl->m_MxNMultiWidget->SetInteractionScheme(scheme); + QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(scheme); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidgetEditor::SetFocus() { - if (nullptr != m_Impl->m_MxNMultiWidget) + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) { - m_Impl->m_MxNMultiWidget->setFocus(); + multiWidget->setFocus(); } } void QmitkMxNMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { - if (nullptr == m_Impl->m_MxNMultiWidget) - { - QHBoxLayout* layout = new QHBoxLayout(parent); - layout->setContentsMargins(0, 0, 0, 0); + QHBoxLayout *layout = new QHBoxLayout(parent); + layout->setContentsMargins(0, 0, 0, 0); - berry::IBerryPreferences* preferences = dynamic_cast(GetPreferences().GetPointer()); - mitk::BaseRenderer::RenderingMode::Type renderingMode = static_cast(preferences->GetInt("Rendering Mode", 0)); + berry::IBerryPreferences *preferences = dynamic_cast(GetPreferences().GetPointer()); - m_Impl->m_MxNMultiWidget = new QmitkMxNMultiWidget(parent, nullptr, nullptr, renderingMode); + auto multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + mitk::BaseRenderer::RenderingMode::Type renderingMode = + static_cast(preferences->GetInt("Rendering Mode", 0)); + multiWidget = new QmitkMxNMultiWidget(parent, 0, nullptr, renderingMode); // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves in PACS mode if (nullptr == m_Impl->m_InteractionSchemeToolBar) { m_Impl->m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); layout->addWidget(m_Impl->m_InteractionSchemeToolBar); } - m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(m_Impl->m_MxNMultiWidget->GetInteractionEventHandler()); + m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(multiWidget->GetInteractionEventHandler()); // show / hide PACS mouse mode interaction scheme toolbar bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); m_Impl->m_InteractionSchemeToolBar->setVisible(PACSInteractionScheme); - // add center widget: the mxn multi widget - layout->addWidget(m_Impl->m_MxNMultiWidget); + multiWidget->SetDataStorage(GetDataStorage()); + multiWidget->InitializeMultiWidget(); + SetMultiWidget(multiWidget); + } - m_Impl->m_MxNMultiWidget->SetDataStorage(GetDataStorage()); - m_Impl->m_MxNMultiWidget->InitializeRenderWindowWidgets(); + layout->addWidget(multiWidget); - // create right toolbar: configuration toolbar to change the render window widget layout - if (nullptr == m_Impl->m_ConfigurationToolBar) - { - m_Impl->m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(); - layout->addWidget(m_Impl->m_ConfigurationToolBar); - } - - connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::LayoutSet, this, &QmitkMxNMultiWidgetEditor::OnLayoutSet); - connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::Synchronized, this, &QmitkMxNMultiWidgetEditor::OnSynchronize); - connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::InteractionSchemeChanged, this, &QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged); + // create right toolbar: configuration toolbar to change the render window widget layout + if (nullptr == m_Impl->m_ConfigurationToolBar) + { + m_Impl->m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(multiWidget); + layout->addWidget(m_Impl->m_ConfigurationToolBar); + } - m_Impl->m_MultiWidgetDecorationManager = std::make_unique(m_Impl->m_MxNMultiWidget); + connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::LayoutSet, + this, &QmitkMxNMultiWidgetEditor::OnLayoutSet); + connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::Synchronized, + this, &QmitkMxNMultiWidgetEditor::OnSynchronize); + connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::InteractionSchemeChanged, + this, &QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged); - GetSite()->GetPage()->AddPartListener(this); + GetSite()->GetPage()->AddPartListener(this); - OnPreferencesChanged(preferences); - } + OnPreferencesChanged(preferences); } void QmitkMxNMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { - if (m_Impl->m_MxNMultiWidget->GetRenderWindowWidgets().empty()) + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) { return; } // update decoration preferences - m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); + //m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); // zooming and panning preferences bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); OnInteractionSchemeChanged(PACSInteractionScheme ? mitk::InteractionSchemeSwitcher::PACSStandard : mitk::InteractionSchemeSwitcher::MITKStandard); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h index cbe79e2eb0..e5022c5c27 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h @@ -1,121 +1,64 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKMXNMULTIWIDGETEDITOR_H #define QMITKMXNMULTIWIDGETEDITOR_H -#include -#include - #include -// berry -#include - -#include +#include +// c++ #include class QmitkMxNMultiWidget; -class MXNMULTIWIDGETEDITOR_EXPORT QmitkMxNMultiWidgetEditor final : public QmitkAbstractRenderEditor, public berry::IPartListener +class MXNMULTIWIDGETEDITOR_EXPORT QmitkMxNMultiWidgetEditor final : public QmitkAbstractMultiWidgetEditor { Q_OBJECT public: - berryObjectMacro(QmitkMxNMultiWidgetEditor) - static const QString EDITOR_ID; QmitkMxNMultiWidgetEditor(); ~QmitkMxNMultiWidgetEditor() override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - QmitkRenderWindow* GetActiveQmitkRenderWindow() const override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - QHash GetQmitkRenderWindows() const override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - bool IsDecorationEnabled(const QString& decoration) const override; - /** - * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart - */ - QStringList GetDecorations() const override; - /** - * @brief Overridden from berry::IPartListener - */ - berry::IPartListener::Events::Types GetPartEventTypes() const override; - /** - * @brief Overridden from berry::IPartListener - */ - void PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) override; - /** - * @brief Overridden from berry::IPartListener - */ - void PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) override; - - /** - * @brief Return the current MxN multi widget of this editor. - */ - QmitkMxNMultiWidget* GetMxNMultiWidget(); - -private Q_SLOTS: + virtual QmitkLevelWindowWidget* GetLevelWindowWidget() const override { return nullptr; } void OnLayoutSet(int row, int column); - void OnSynchronize(bool synchronized); void OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); private: /** * @brief Overridden from QmitkAbstractRenderEditor */ void SetFocus() override; /** * @brief Overridden from QmitkAbstractRenderEditor */ void CreateQtPartControl(QWidget* parent) override; /** * @brief Overridden from QmitkAbstractRenderEditor */ void OnPreferencesChanged(const berry::IBerryPreferences* preferences) override; - class Impl; - const std::unique_ptr m_Impl; + struct Impl; + std::unique_ptr m_Impl; + }; #endif // QMITKMXNMULTIWIDGETEDITOR_H diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp b/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp index 3f99a45f20..b23429886c 100755 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/src/internal/QmitkPointSetInteractionView.cpp @@ -1,148 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Qmitk related includes #include "QmitkPointSetInteractionView.h" #include "ui_QmitkPointSetInteractionViewControls.h" #include #include #include #include -#include -#include + #include #include +#include + +#include +#include const std::string QmitkPointSetInteractionView::VIEW_ID = "org.mitk.views.pointsetinteraction"; QmitkPointSetInteractionView::QmitkPointSetInteractionView( QObject* /*parent*/ ) : m_Controls(nullptr) { } QmitkPointSetInteractionView::~QmitkPointSetInteractionView() { } void QmitkPointSetInteractionView::CreateQtPartControl( QWidget *parent ) { m_Controls = new Ui::QmitkPointSetInteractionControls; m_Controls->setupUi(parent); m_Controls->m_PbAddPointSet->connect( m_Controls->m_PbAddPointSet, SIGNAL( clicked() ) , this, SLOT( OnAddPointSetClicked() ) ); if (mitk::IRenderWindowPart *renderWindowPart = GetRenderWindowPart()) { // let the point set widget know about the render window part (crosshair updates) RenderWindowPartActivated(renderWindowPart); } } void QmitkPointSetInteractionView::SetFocus() { m_Controls->m_PbAddPointSet->setFocus(); } void QmitkPointSetInteractionView::OnAddPointSetClicked() { //Ask for the name of the point set bool ok = false; QString name = QInputDialog::getText( QApplication::activeWindow() , tr("Add point set..."), tr("Enter name for the new point set"), QLineEdit::Normal, tr("PointSet"), &ok ); if ( ! ok || name.isEmpty() ) return; // //Create a new empty pointset // mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); // // Create a new data tree node // mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); // // fill the data tree node with the appropriate information // pointSetNode->SetData( pointSet ); pointSetNode->SetProperty( "name", mitk::StringProperty::New( name.toStdString() ) ); pointSetNode->SetProperty( "opacity", mitk::FloatProperty::New( 1 ) ); pointSetNode->SetColor( 1.0, 1.0, 0.0 ); // // add the node to the ds // this->GetDataStorage()->Add(pointSetNode); // make new selection and emulate selection for this berry::IWorkbenchPart::Pointer nullPart; QList selection; selection.push_back(pointSetNode); this->OnSelectionChanged(nullPart, selection); } void QmitkPointSetInteractionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { mitk::DataNode::Pointer selectedNode; if(!nodes.empty()) selectedNode = nodes.front(); mitk::PointSet::Pointer pointSet; if(selectedNode.IsNotNull()) pointSet = dynamic_cast(selectedNode->GetData()); if (pointSet.IsNotNull()) { m_SelectedPointSetNode = selectedNode; m_Controls->m_CurrentPointSetLabel->setText(QString::fromStdString(selectedNode->GetName())); m_Controls->m_PointListWidget->SetPointSetNode(selectedNode); } else { m_Controls->m_CurrentPointSetLabel->setText(tr("None")); m_Controls->m_PointListWidget->SetPointSetNode(nullptr); } } void QmitkPointSetInteractionView::NodeChanged( const mitk::DataNode* node ) { if(node == m_SelectedPointSetNode && m_Controls->m_CurrentPointSetLabel->text().toStdString() != node->GetName()) { m_Controls->m_CurrentPointSetLabel->setText(QString::fromStdString(node->GetName())); } } void QmitkPointSetInteractionView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if(m_Controls) { m_Controls->m_PointListWidget->AddSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); m_Controls->m_PointListWidget->AddSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); m_Controls->m_PointListWidget->AddSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); } } void QmitkPointSetInteractionView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { if(m_Controls) { m_Controls->m_PointListWidget->RemoveSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); m_Controls->m_PointListWidget->RemoveSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); m_Controls->m_PointListWidget->RemoveSliceNavigationController(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); } } diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp index 591643dc1b..bf99727118 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp @@ -1,460 +1,461 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPreprocessingResamplingView.h" // QT includes (GUI) #include #include #include #include #include #include #include // Berry includes (selection service) #include #include // MITK includes (GUI) #include "QmitkStdMultiWidget.h" #include "QmitkDataNodeSelectionProvider.h" #include "mitkDataNodeObject.h" // MITK includes (general) #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkImageTimeSelector.h" #include "mitkVectorImageMapper2D.h" #include "mitkProperties.h" +#include "mitkLevelWindowProperty.h" // Includes for image casting between ITK and MITK #include "mitkImageCast.h" #include "mitkITKImageImport.h" // ITK includes (general) #include #include // Resampling #include #include #include #include #include #include #include // STD #include // Convenient Definitions typedef itk::Image ImageType; typedef itk::Image SegmentationImageType; typedef itk::Image DoubleImageType; typedef itk::Image, 3> VectorImageType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType2; typedef itk::CastImageFilter< ImageType, DoubleImageType > ImagePTypeToFloatPTypeCasterType; typedef itk::LinearInterpolateImageFunction< ImageType, double > LinearInterpolatorType; typedef itk::NearestNeighborInterpolateImageFunction< ImageType, double > NearestInterpolatorType; typedef itk::BSplineInterpolateImageFunction BSplineInterpolatorType; QmitkPreprocessingResampling::QmitkPreprocessingResampling() : QmitkAbstractView(), m_Controls(nullptr), m_SelectedImageNode(nullptr), m_TimeStepperAdapter(nullptr) { } QmitkPreprocessingResampling::~QmitkPreprocessingResampling() { } void QmitkPreprocessingResampling::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkPreprocessingResamplingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); } m_SelectedImageNode = mitk::DataStorageSelection::New(this->GetDataStorage(), false); // Setup Controls this->m_Controls->cbParam4->clear(); this->m_Controls->cbParam4->insertItem(LINEAR, "Linear"); this->m_Controls->cbParam4->insertItem(NEAREST, "Nearest neighbor"); this->m_Controls->cbParam4->insertItem(SPLINE, "B-Spline"); } void QmitkPreprocessingResampling::CreateConnections() { if ( m_Controls ) { connect((QObject*)(m_Controls->btnDoIt), SIGNAL(clicked()), (QObject*) this, SLOT(StartButtonClicked())); connect((QObject*)(m_Controls->buttonExecuteOnMultipleImages), SIGNAL(clicked()), (QObject*) this, SLOT(StartMultipleImagesButtonClicked())); connect( (QObject*)(m_Controls->cbParam4), SIGNAL( activated(int) ), this, SLOT( SelectInterpolator(int) ) ); } } void QmitkPreprocessingResampling::InternalGetTimeNavigationController() { auto renwin_part = GetRenderWindowPart(); if( renwin_part != nullptr ) { auto tnc = renwin_part->GetTimeNavigationController(); if( tnc != nullptr ) { m_TimeStepperAdapter = new QmitkStepperAdapter((QObject*) m_Controls->sliceNavigatorTime, tnc->GetTime(), "sliceNavigatorTimeFromBIP"); } } } void QmitkPreprocessingResampling::SetFocus() { } //datamanager selection changed void QmitkPreprocessingResampling::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { ResetOneImageOpPanel(); //any nodes there? if (!nodes.empty()) { // reset GUI m_Controls->sliceNavigatorTime->setEnabled(false); m_Controls->leImage1->setText(tr("Select an Image in Data Manager")); m_SelectedNodes.clear(); for (mitk::DataNode* _DataNode : nodes) { m_SelectedImageNode->RemoveAllNodes(); *m_SelectedImageNode = _DataNode; mitk::Image::Pointer tempImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); //no image if (tempImage.IsNull() || (tempImage->IsInitialized() == false)) { if (m_SelectedNodes.size() < 1) { m_Controls->leImage1->setText(tr("Not an image.")); } continue; } //2D image if (tempImage->GetDimension() < 3) { if (m_SelectedNodes.size() < 1) { m_Controls->leImage1->setText(tr("2D images are not supported.")); } continue; } if (m_SelectedNodes.size() < 1) { m_Controls->leImage1->setText(QString(m_SelectedImageNode->GetNode()->GetName().c_str())); mitk::Vector3D aSpacing = tempImage->GetGeometry()->GetSpacing(); std::string text("x-spacing (" + std::to_string(aSpacing[0]) + ")"); m_Controls->tlParam1->setText(text.c_str()); text = "y-spacing (" + std::to_string(aSpacing[1]) + ")"; m_Controls->tlParam2->setText(text.c_str()); text = "z-spacing (" + std::to_string(aSpacing[2]) + ")"; m_Controls->tlParam3->setText(text.c_str()); if (tempImage->GetDimension() > 3) { // try to retrieve the TNC (for 4-D Processing ) this->InternalGetTimeNavigationController(); m_Controls->sliceNavigatorTime->setEnabled(true); m_Controls->tlTime->setEnabled(true); } } m_SelectedNodes.push_back(_DataNode); } if (m_SelectedNodes.size() > 0) { *m_SelectedImageNode = m_SelectedNodes[0]; } ResetParameterPanel(); } } void QmitkPreprocessingResampling::ResetOneImageOpPanel() { m_Controls->tlTime->setEnabled(false); m_Controls->btnDoIt->setEnabled(false); m_Controls->buttonExecuteOnMultipleImages->setEnabled(false); m_Controls->cbHideOrig->setEnabled(false); m_Controls->leImage1->setText(tr("Select an Image in Data Manager")); m_Controls->tlParam1->setText("x-spacing"); m_Controls->tlParam1->setText("y-spacing"); m_Controls->tlParam1->setText("z-spacing"); } void QmitkPreprocessingResampling::ResetParameterPanel() { m_Controls->btnDoIt->setEnabled(true); m_Controls->buttonExecuteOnMultipleImages->setEnabled(true); m_Controls->cbHideOrig->setEnabled(true); } void QmitkPreprocessingResampling::ResetTwoImageOpPanel() { } void QmitkPreprocessingResampling::StartMultipleImagesButtonClicked() { for (auto currentSelectedNode : m_SelectedNodes) { m_SelectedImageNode->RemoveAllNodes(); *m_SelectedImageNode = currentSelectedNode; StartButtonClicked(); } } void QmitkPreprocessingResampling::StartButtonClicked() { if(!m_SelectedImageNode->GetNode()) return; this->BusyCursorOn(); mitk::Image::Pointer newImage; try { newImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); } catch ( std::exception &e ) { QString exceptionString = tr("An error occured during image loading:\n"); exceptionString.append( e.what() ); QMessageBox::warning( nullptr, "Preprocessing - Resampling: ", exceptionString , QMessageBox::Ok, QMessageBox::NoButton ); this->BusyCursorOff(); return; } // check if input image is valid, casting does not throw exception when casting from 'NULL-Object' if ( (! newImage) || (newImage->IsInitialized() == false) ) { this->BusyCursorOff(); QMessageBox::warning( nullptr, "Preprocessing - Resampling", tr("Input image is broken or not initialized. Returning."), QMessageBox::Ok, QMessageBox::NoButton ); return; } // check if operation is done on 4D a image time step if(newImage->GetDimension() > 3) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(newImage); timeSelector->SetTimeNr( ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos() ); timeSelector->Update(); newImage = timeSelector->GetOutput(); } // check if image or vector image ImageType::Pointer itkImage = ImageType::New(); VectorImageType::Pointer itkVecImage = VectorImageType::New(); int isVectorImage = newImage->GetPixelType().GetNumberOfComponents(); if(isVectorImage > 1) { CastToItkImage( newImage, itkVecImage ); } else { CastToItkImage( newImage, itkImage ); } std::stringstream nameAddition(""); double dparam1 = m_Controls->dsbParam1->value(); double dparam2 = m_Controls->dsbParam2->value(); double dparam3 = m_Controls->dsbParam3->value(); try{ std::string selectedInterpolator; ResampleImageFilterType::Pointer resampler = ResampleImageFilterType::New(); switch (m_SelectedInterpolation) { case LINEAR: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } case NEAREST: { NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Nearest"; break; } case SPLINE: { BSplineInterpolatorType::Pointer interpolator = BSplineInterpolatorType::New(); interpolator->SetSplineOrder(3); resampler->SetInterpolator(interpolator); selectedInterpolator = "B-Spline"; break; } default: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } } resampler->SetInput( itkImage ); resampler->SetOutputOrigin( itkImage->GetOrigin() ); ImageType::SizeType input_size = itkImage->GetLargestPossibleRegion().GetSize(); ImageType::SpacingType input_spacing = itkImage->GetSpacing(); ImageType::SizeType output_size; ImageType::SpacingType output_spacing; if (dparam1 > 0) { output_size[0] = std::ceil(input_size[0] * (input_spacing[0] / dparam1)); output_spacing[0] = dparam1; } else { output_size[0] = std::ceil(input_size[0] * (-1.0 / dparam1)); output_spacing[0] = -1.0*input_spacing[0] * dparam1; } if (dparam2 > 0) { output_size[1] = std::ceil(input_size[1] * (input_spacing[1] / dparam2)); output_spacing[1] = dparam2; } else { output_size[1] = std::ceil(input_size[1] * (-1.0 / dparam2)); output_spacing[1] = -1.0*input_spacing[1] * dparam2; } if (dparam3 > 0) { output_size[2] = std::ceil(input_size[2] * (input_spacing[2] / dparam3)); output_spacing[2] = dparam3; } else { output_size[2] = std::ceil(input_size[2] * (-1.0 / dparam3)); output_spacing[2] = -1.0*input_spacing[2] * dparam3; } resampler->SetSize( output_size ); resampler->SetOutputSpacing( output_spacing ); resampler->SetOutputDirection( itkImage->GetDirection() ); resampler->UpdateLargestPossibleRegion(); ImageType::Pointer resampledImage = resampler->GetOutput(); newImage = mitk::ImportItkImage( resampledImage )->Clone(); nameAddition << "_Resampled_" << selectedInterpolator; std::cout << "Resampling successful." << std::endl; } catch (...) { this->BusyCursorOff(); QMessageBox::warning(nullptr, "Warning", "Problem when applying filter operation. Check your input..."); return; } newImage->DisconnectPipeline(); // adjust level/window to new image mitk::LevelWindow levelwindow; levelwindow.SetAuto( newImage ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); // compose new image name std::string name = m_SelectedImageNode->GetNode()->GetName(); if (name.find(".pic.gz") == name.size() -7 ) { name = name.substr(0,name.size() -7); } name.append( nameAddition.str() ); // create final result MITK data storage node mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "levelwindow", levWinProp ); result->SetProperty( "name", mitk::StringProperty::New( name.c_str() ) ); result->SetData( newImage ); // for vector images, a different mapper is needed if(isVectorImage > 1) { mitk::VectorImageMapper2D::Pointer mapper = mitk::VectorImageMapper2D::New(); result->SetMapper(1,mapper); } // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result, m_SelectedImageNode->GetNode() ); if ( m_Controls->cbHideOrig->isChecked() == true ) m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); // show the results mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->BusyCursorOff(); } void QmitkPreprocessingResampling::SelectInterpolator(int interpolator) { switch (interpolator) { case 0: { m_SelectedInterpolation = LINEAR; break; } case 1: { m_SelectedInterpolation = NEAREST; break; } case 2: { m_SelectedInterpolation = SPLINE; } } } diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp index d5cdc23bca..99d3386a59 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp @@ -1,125 +1,168 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager plugin #include "QmitkRenderWindowManagerView.h" // mitk core #include #include #include +// mitk qt widgets +#include +#include + +// mitk gui qt common plugin +#include + const std::string QmitkRenderWindowManagerView::VIEW_ID = "org.mitk.views.renderwindowmanager"; void QmitkRenderWindowManagerView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; SetControlledRenderer(); + + // if the render window part is an abstract multi widget editor we can receive the abstract multi widget and listen to the signal + auto abstractMultiWidgetEditor = dynamic_cast(m_RenderWindowPart); + if (nullptr != abstractMultiWidgetEditor) + { + connect(abstractMultiWidgetEditor->GetMultiWidget(), &QmitkAbstractMultiWidget::ActiveRenderWindowChanged, this, &QmitkRenderWindowManagerView::RenderWindowChanged); + } } } void QmitkRenderWindowManagerView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart == renderWindowPart) { + // if the render window part is an abstract multi widget editor we need to disconnect the signal before release the render window part + auto abstractMultiWidgetEditor = dynamic_cast(m_RenderWindowPart); + if (nullptr != abstractMultiWidgetEditor) + { + disconnect(abstractMultiWidgetEditor->GetMultiWidget(), &QmitkAbstractMultiWidget::ActiveRenderWindowChanged, this, &QmitkRenderWindowManagerView::RenderWindowChanged); + } + m_RenderWindowPart = nullptr; SetControlledRenderer(); } } void QmitkRenderWindowManagerView::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart == renderWindowPart) { SetControlledRenderer(); } } void QmitkRenderWindowManagerView::SetFocus() { // nothing here } void QmitkRenderWindowManagerView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; // create GUI widgets m_Controls.setupUi(parent); // add custom render window manager UI widget to the 'renderWindowManagerTab' m_RenderWindowInspector = new QmitkRenderWindowDataStorageInspector(parent); m_RenderWindowInspector->SetDataStorage(GetDataStorage()); m_RenderWindowInspector->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); m_Controls.verticalLayout->addWidget(m_RenderWindowInspector); // data node context menu and menu actions m_InspectorView = m_RenderWindowInspector->GetView(); m_DataNodeContextMenu = new QmitkDataNodeContextMenu(GetSite(), m_InspectorView); m_DataNodeContextMenu->SetDataStorage(GetDataStorage()); //m_DataNodeContextMenu->SetSurfaceDecimation(m_SurfaceDecimation); // connect objects connect(m_Controls.comboBoxRenderWindowSelection, static_cast(&QComboBox::currentIndexChanged), this, &QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged); connect(m_InspectorView, &QAbstractItemView::customContextMenuRequested, m_DataNodeContextMenu, &QmitkDataNodeContextMenu::OnContextMenuRequested); m_RenderWindowPart = GetRenderWindowPart(); // also sets the controlled renderer SetControlledRenderer(); } void QmitkRenderWindowManagerView::SetControlledRenderer() { QHash renderWindows; - if (m_RenderWindowPart != nullptr) + if (nullptr != m_RenderWindowPart) { renderWindows = m_RenderWindowPart->GetQmitkRenderWindows(); } mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer; QStringList rendererNames; m_Controls.comboBoxRenderWindowSelection->clear(); mitk::BaseRenderer* baseRenderer = nullptr; for (const auto& renderWindow : renderWindows.values()) { baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow()); if (nullptr != baseRenderer) { controlledRenderer.push_back(baseRenderer); rendererNames.append(baseRenderer->GetName()); } } m_RenderWindowInspector->SetControlledRenderer(controlledRenderer); rendererNames.sort(); m_Controls.comboBoxRenderWindowSelection->addItems(rendererNames); } void QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged(const QString& renderWindowId) { m_RenderWindowInspector->SetActiveRenderWindow(renderWindowId); mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(renderWindowId.toStdString()); if (nullptr != selectedRenderer) { m_DataNodeContextMenu->SetBaseRenderer(selectedRenderer); } + + // if the render window part is an abstract multi widget editor we can set the active render window + auto abstractMultiWidgetEditor = dynamic_cast(m_RenderWindowPart); + if (nullptr != abstractMultiWidgetEditor) + { + + auto renderWindowWidget = abstractMultiWidgetEditor->GetMultiWidget()->GetRenderWindowWidget(renderWindowId); + abstractMultiWidgetEditor->GetMultiWidget()->SetActiveRenderWindowWidget(renderWindowWidget); + } +} + +void QmitkRenderWindowManagerView::RenderWindowChanged() +{ + auto abstractMultiWidget = dynamic_cast(sender()); + if (nullptr != abstractMultiWidget) + { + auto activeRenderWindowWidget = abstractMultiWidget->GetActiveRenderWindowWidget(); + if (nullptr != activeRenderWindowWidget) + { + m_Controls.comboBoxRenderWindowSelection->setCurrentText(activeRenderWindowWidget->GetWidgetName()); + } + } } QItemSelectionModel* QmitkRenderWindowManagerView::GetDataNodeSelectionModel() const { return m_InspectorView->selectionModel(); } diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h index b1a383464e..ac4b3b4a4b 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h @@ -1,81 +1,83 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWMANAGERVIEW_H #define QMITKRENDERWINDOWMANAGERVIEW_H // render window manager plugin #include "ui_QmitkRenderWindowManagerControls.h" // render window manager UI module #include // mitk gui qt application #include // mitk gui common plugin #include // mitk gui qt common plugin #include /** * @brief RenderWindowManager */ class QmitkRenderWindowManagerView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) override; protected: void SetFocus() override; void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: /** * @brief Called when the user changes the render window selection in the combo box. * * @param renderWindowId The text inside the combo box. */ void OnRenderWindowSelectionChanged(const QString& renderWindowId); private: void SetControlledRenderer(); + void RenderWindowChanged(); + QWidget* m_Parent; Ui::QmitkRenderWindowManagerControls m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; QmitkRenderWindowDataStorageInspector* m_RenderWindowInspector; QAbstractItemView* m_InspectorView; QmitkDataNodeContextMenu* m_DataNodeContextMenu; QItemSelectionModel* GetDataNodeSelectionModel() const override; }; #endif // QMITKRENDERWINDOWMANAGERVIEW_H diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp index 5504695e80..ec3c92b0ed 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp @@ -1,557 +1,410 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkStdMultiWidgetEditor.h" #include #include #include -#include #include -#include - #include #include #include #include #include -#include +// mitk qt widgets module +#include +#include +#include #include -class QmitkStdMultiWidgetEditorPrivate -{ -public: - - QmitkStdMultiWidgetEditorPrivate(); - ~QmitkStdMultiWidgetEditorPrivate(); +// mitk gui qt common plugin +#include - QmitkStdMultiWidget* m_StdMultiWidget; - QmitkMouseModeSwitcher* m_MouseModeToolbar; - /** - * @brief Members for the MultiWidget decorations. - */ - QString m_WidgetBackgroundColor1[4]; - QString m_WidgetBackgroundColor2[4]; - QString m_WidgetDecorationColor[4]; - QString m_WidgetAnnotation[4]; - bool m_MenuWidgetsEnabled; - QScopedPointer m_PartListener; - - QHash m_RenderWindows; - -}; +const QString QmitkStdMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.stdmultiwidget"; -struct QmitkStdMultiWidgetPartListener : public berry::IPartListener +struct QmitkStdMultiWidgetEditor::Impl final { - QmitkStdMultiWidgetPartListener(QmitkStdMultiWidgetEditorPrivate* dd) - : d(dd) - {} + Impl(); + ~Impl() = default; - Events::Types GetPartEventTypes() const override - { - return Events::CLOSED | Events::HIDDEN | Events::VISIBLE | Events::OPENED; - } - - void PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) override - { - if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) - { - QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); - - if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) - { - d->m_StdMultiWidget->RemovePlanesFromDataStorage(); - stdMultiWidgetEditor->RequestActivateMenuWidget(false); - } - } - } - - void PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) override - { - if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) - { - QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); - - if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) - { - stdMultiWidgetEditor->RequestActivateMenuWidget(false); - } - } - } - - void PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) override - { - if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) - { - QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); - - if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) - { - stdMultiWidgetEditor->RequestActivateMenuWidget(true); - } - } - } - - void PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) override - { - if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) - { - QmitkStdMultiWidgetEditor::Pointer stdMultiWidgetEditor = partRef->GetPart(false).Cast(); - - if (d->m_StdMultiWidget == stdMultiWidgetEditor->GetStdMultiWidget()) - { - d->m_StdMultiWidget->AddPlanesToDataStorage(); - stdMultiWidgetEditor->RequestActivateMenuWidget(true); - } - } - } - -private: - - QmitkStdMultiWidgetEditorPrivate* const d; + QmitkInteractionSchemeToolBar* m_InteractionSchemeToolBar; + QmitkLevelWindowWidget* m_LevelWindowWidget; + std::unique_ptr m_MultiWidgetDecorationManager; }; -QmitkStdMultiWidgetEditorPrivate::QmitkStdMultiWidgetEditorPrivate() - : m_StdMultiWidget(nullptr), m_MouseModeToolbar(nullptr) - , m_MenuWidgetsEnabled(false) - , m_PartListener(new QmitkStdMultiWidgetPartListener(this)) -{} - -QmitkStdMultiWidgetEditorPrivate::~QmitkStdMultiWidgetEditorPrivate() +QmitkStdMultiWidgetEditor::Impl::Impl() + : m_InteractionSchemeToolBar(nullptr) + , m_LevelWindowWidget(nullptr) { + // nothing here } -const QString QmitkStdMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.stdmultiwidget"; - +////////////////////////////////////////////////////////////////////////// +// QmitkStdMultiWidgetEditor +////////////////////////////////////////////////////////////////////////// QmitkStdMultiWidgetEditor::QmitkStdMultiWidgetEditor() - : d(new QmitkStdMultiWidgetEditorPrivate) + : QmitkAbstractMultiWidgetEditor() + , m_Impl(std::make_unique()) { + // nothing here } QmitkStdMultiWidgetEditor::~QmitkStdMultiWidgetEditor() { - this->GetSite()->GetPage()->RemovePartListener(d->m_PartListener.data()); + GetSite()->GetPage()->RemovePartListener(this); } -QmitkStdMultiWidget* QmitkStdMultiWidgetEditor::GetStdMultiWidget() +berry::IPartListener::Events::Types QmitkStdMultiWidgetEditor::GetPartEventTypes() const { - return d->m_StdMultiWidget; + return Events::CLOSED | Events::OPENED | Events::HIDDEN | Events::VISIBLE; } -QmitkRenderWindow *QmitkStdMultiWidgetEditor::GetActiveQmitkRenderWindow() const +void QmitkStdMultiWidgetEditor::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) { - if (d->m_StdMultiWidget) return d->m_StdMultiWidget->GetRenderWindow1(); - return nullptr; + if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) + { + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr != multiWidget) + { + multiWidget->RemovePlanesFromDataStorage(); + multiWidget->ActivateMenuWidget(false); + } + } } -QHash QmitkStdMultiWidgetEditor::GetQmitkRenderWindows() const +void QmitkStdMultiWidgetEditor::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) { - return d->m_RenderWindows; + if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) + { + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr != multiWidget) + { + multiWidget->AddPlanesToDataStorage(); + multiWidget->ActivateMenuWidget(true); + } + } } -QmitkRenderWindow *QmitkStdMultiWidgetEditor::GetQmitkRenderWindow(const QString &id) const +void QmitkStdMultiWidgetEditor::PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) { - if (d->m_RenderWindows.contains(id)) - return d->m_RenderWindows[id]; - - return nullptr; + if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) + { + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr != multiWidget) + { + multiWidget->ActivateMenuWidget(false); + } + } } -mitk::Point3D QmitkStdMultiWidgetEditor::GetSelectedPosition(const QString & /*id*/) const +void QmitkStdMultiWidgetEditor::PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) { - return d->m_StdMultiWidget->GetCrossPosition(); + if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) + { + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr != multiWidget) + { + multiWidget->ActivateMenuWidget(true); + } + } } -void QmitkStdMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D &pos, const QString &/*id*/) +QmitkLevelWindowWidget* QmitkStdMultiWidgetEditor::GetLevelWindowWidget() const { - d->m_StdMultiWidget->MoveCrossToPosition(pos); + return m_Impl->m_LevelWindowWidget; } -void QmitkStdMultiWidgetEditor::EnableDecorations(bool enable, const QStringList &decorations) +void QmitkStdMultiWidgetEditor::EnableSlicingPlanes(bool enable) { - if (decorations.isEmpty() || decorations.contains(DECORATION_BORDER)) - { - enable ? d->m_StdMultiWidget->EnableColoredRectangles() - : d->m_StdMultiWidget->DisableColoredRectangles(); - } - if (decorations.isEmpty() || decorations.contains(DECORATION_LOGO)) + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr == multiWidget) { - enable ? d->m_StdMultiWidget->EnableDepartmentLogo() - : d->m_StdMultiWidget->DisableDepartmentLogo(); + return; } - if (decorations.isEmpty() || decorations.contains(DECORATION_MENU)) + + multiWidget->SetWidgetPlanesVisibility(enable); +} + +bool QmitkStdMultiWidgetEditor::IsSlicingPlanesEnabled() const +{ + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr == multiWidget) { - d->m_StdMultiWidget->ActivateMenuWidget(enable); + return false; } - if (decorations.isEmpty() || decorations.contains(DECORATION_BACKGROUND)) + + mitk::DataNode::Pointer node = multiWidget->GetWidgetPlane1(); + if (node.IsNotNull()) { - enable ? d->m_StdMultiWidget->EnableGradientBackground() - : d->m_StdMultiWidget->DisableGradientBackground(); + bool visible = false; + node->GetVisibility(visible, nullptr); + return visible; } - if (decorations.isEmpty() || decorations.contains(DECORATION_CORNER_ANNOTATION)) + else { - enable ? d->m_StdMultiWidget->SetCornerAnnotationVisibility(true) - : d->m_StdMultiWidget->SetCornerAnnotationVisibility(false); + return false; } } -bool QmitkStdMultiWidgetEditor::IsDecorationEnabled(const QString &decoration) const +void QmitkStdMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { - if (decoration == DECORATION_BORDER) - { - return d->m_StdMultiWidget->IsColoredRectanglesEnabled(); - } - else if (decoration == DECORATION_LOGO) + const auto& multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) { - return d->m_StdMultiWidget->IsColoredRectanglesEnabled(); + return; } - else if (decoration == DECORATION_MENU) - { - return d->m_StdMultiWidget->IsMenuWidgetEnabled(); - } - else if (decoration == DECORATION_BACKGROUND) + + if (mitk::InteractionSchemeSwitcher::PACSStandard == scheme) { - return d->m_StdMultiWidget->GetGradientBackgroundFlag(); + m_Impl->m_InteractionSchemeToolBar->setVisible(true); } - else if (decoration == DECORATION_CORNER_ANNOTATION) + else { - return d->m_StdMultiWidget->IsCornerAnnotationVisible(); + m_Impl->m_InteractionSchemeToolBar->setVisible(false); } - return false; -} - -QStringList QmitkStdMultiWidgetEditor::GetDecorations() const -{ - QStringList decorations; - decorations << DECORATION_BORDER << DECORATION_LOGO << DECORATION_MENU << DECORATION_BACKGROUND << DECORATION_CORNER_ANNOTATION; - return decorations; -} - -void QmitkStdMultiWidgetEditor::EnableSlicingPlanes(bool enable) -{ - d->m_StdMultiWidget->SetWidgetPlanesVisibility(enable); + QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(scheme); } -bool QmitkStdMultiWidgetEditor::IsSlicingPlanesEnabled() const +void QmitkStdMultiWidgetEditor::ShowLevelWindowWidget(bool show) { - mitk::DataNode::Pointer node = this->d->m_StdMultiWidget->GetWidgetPlane1(); - if (node.IsNotNull()) + if (show) { - bool visible = false; - node->GetVisibility(visible, nullptr); - return visible; + m_Impl->m_LevelWindowWidget->disconnect(this); + m_Impl->m_LevelWindowWidget->SetDataStorage(GetDataStorage()); + m_Impl->m_LevelWindowWidget->show(); } else { - return false; + m_Impl->m_LevelWindowWidget->disconnect(this); + m_Impl->m_LevelWindowWidget->hide(); + } +} + +void QmitkStdMultiWidgetEditor::SetFocus() +{ + const auto& multiWidget = GetMultiWidget(); + if (nullptr != multiWidget) + { + multiWidget->setFocus(); } } void QmitkStdMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { - if (d->m_StdMultiWidget == nullptr) + QHBoxLayout* layout = new QHBoxLayout(parent); + layout->setContentsMargins(0, 0, 0, 0); + + berry::IBerryPreferences* preferences = dynamic_cast(GetPreferences().GetPointer()); + + auto multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) { - QHBoxLayout* layout = new QHBoxLayout(parent); - layout->setContentsMargins(0,0,0,0); + mitk::BaseRenderer::RenderingMode::Type renderingMode = static_cast(preferences->GetInt("Rendering Mode", 0)); + multiWidget = new QmitkStdMultiWidget(parent, 0, nullptr, renderingMode); - if (d->m_MouseModeToolbar == nullptr) + // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves (in PACS mode) + if (nullptr == m_Impl->m_InteractionSchemeToolBar) { - d->m_MouseModeToolbar = new QmitkMouseModeSwitcher(parent); // delete by Qt via parent - layout->addWidget(d->m_MouseModeToolbar); + m_Impl->m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); + layout->addWidget(m_Impl->m_InteractionSchemeToolBar); } + m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(multiWidget->GetInteractionEventHandler()); - berry::IPreferences::Pointer prefs = this->GetPreferences(); + multiWidget->SetDataStorage(GetDataStorage()); + multiWidget->InitializeMultiWidget(); + SetMultiWidget(multiWidget); + } - mitk::BaseRenderer::RenderingMode::Type renderingMode = static_cast(prefs->GetInt( "Rendering Mode" , 0 )); + layout->addWidget(multiWidget); - d->m_StdMultiWidget = new QmitkStdMultiWidget(parent,nullptr,nullptr,renderingMode); - d->m_RenderWindows.insert("axial", d->m_StdMultiWidget->GetRenderWindow1()); - d->m_RenderWindows.insert("sagittal", d->m_StdMultiWidget->GetRenderWindow2()); - d->m_RenderWindows.insert("coronal", d->m_StdMultiWidget->GetRenderWindow3()); - d->m_RenderWindows.insert("3d", d->m_StdMultiWidget->GetRenderWindow4()); + // create level window slider on the right side + if (nullptr == m_Impl->m_LevelWindowWidget) + { + m_Impl->m_LevelWindowWidget = new QmitkLevelWindowWidget(parent); + m_Impl->m_LevelWindowWidget->setObjectName(QString::fromUtf8("levelWindowWidget")); + + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(m_Impl->m_LevelWindowWidget->sizePolicy().hasHeightForWidth()); + m_Impl->m_LevelWindowWidget->setSizePolicy(sizePolicy); + m_Impl->m_LevelWindowWidget->setMaximumWidth(50); + } - d->m_MouseModeToolbar->setMouseModeSwitcher( d->m_StdMultiWidget->GetMouseModeSwitcher() ); + layout->addWidget(m_Impl->m_LevelWindowWidget); - layout->addWidget(d->m_StdMultiWidget); + m_Impl->m_MultiWidgetDecorationManager = std::make_unique(multiWidget); - mitk::DataStorage::Pointer ds = this->GetDataStorage(); + GetSite()->GetPage()->AddPartListener(this); - // Tell the multiWidget which (part of) the tree to render - d->m_StdMultiWidget->SetDataStorage(ds); + InitializePreferences(preferences); + OnPreferencesChanged(preferences); +} - // Initialize views as axial, sagittal, coronar to all data objects in DataStorage - // (from top-left to bottom) - auto geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); - mitk::RenderingManager::GetInstance()->InitializeViews(geo); +void QmitkStdMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) +{ + const auto& multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr == multiWidget) + { + return; + } - // Initialize bottom-right view as 3D view - d->m_StdMultiWidget->GetRenderWindow4()->GetRenderer()->SetMapperID( - mitk::BaseRenderer::Standard3D ); + // change and apply decoration preferences + GetPreferenceDecorations(preferences); + m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); - // Enable standard handler for levelwindow-slider - d->m_StdMultiWidget->EnableStandardLevelWindow(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = multiWidget->GetRenderWindowWidgets(); + int i = 0; + for (const auto& renderWindowWidget : renderWindowWidgets) + { + auto decorationColor = renderWindowWidget.second->GetDecorationColor(); + multiWidget->SetDecorationColor(i, decorationColor); - // Add the displayed views to the tree to see their positions - // in 2D and 3D - d->m_StdMultiWidget->AddDisplayPlaneSubTree(); + ++i; + } - //d->m_StdMultiWidget->EnableNavigationControllerEventListening(); + int crosshairgapsize = preferences->GetInt("crosshair gap size", 32); + multiWidget->GetWidgetPlane1()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); + multiWidget->GetWidgetPlane2()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); + multiWidget->GetWidgetPlane3()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); - // Store the initial visibility status of the menu widget. - d->m_MenuWidgetsEnabled = d->m_StdMultiWidget->IsMenuWidgetEnabled(); + // zooming and panning preferences + bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); + mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); - this->GetSite()->GetPage()->AddPartListener(d->m_PartListener.data()); + // mouse modes switcher toolbar + bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); + OnInteractionSchemeChanged(PACSInteractionScheme ? + mitk::InteractionSchemeSwitcher::PACSStandard : + mitk::InteractionSchemeSwitcher::MITKStandard); - berry::IBerryPreferences* berryprefs = dynamic_cast(prefs.GetPointer()); - InitializePreferences(berryprefs); - this->OnPreferencesChanged(berryprefs); + // level window setting + bool showLevelWindowWidget = preferences->GetBool("Show level/window widget", true); + ShowLevelWindowWidget(showLevelWindowWidget); - this->RequestUpdate(); - } + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkStdMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* prefs) +void QmitkStdMultiWidgetEditor::InitializePreferences(berry::IBerryPreferences * preferences) { - // Enable change of logo. If no DepartmentLogo was set explicitly, MBILogo is used. - // Set new department logo by prefs->Set("DepartmentLogo", "PathToImage"); + auto multiWidget = GetMultiWidget(); + if (nullptr == multiWidget) + { + return; + } - // If no logo was set for this plug-in specifically, walk the parent preference nodes - // and lookup a logo value there. + GetPreferenceDecorations(preferences); //overwrite if preferences are defined - //We need to disable the logo first, otherwise setting a new logo will have no effect due to how mitkManufacturerLogo works - d->m_StdMultiWidget->DisableDepartmentLogo(); - d->m_StdMultiWidget->SetDepartmentLogo(qPrintable(":/org.mitk.gui.qt.stdmultiwidgeteditor/defaultWatermark.png")); - d->m_StdMultiWidget->EnableDepartmentLogo(); + QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = multiWidget->GetRenderWindowWidgets(); + int i = 0; + for (const auto& renderWindowWidget : renderWindowWidgets) + { + QString widgetName = "widget" + QString::number(i + 1); - const berry::IPreferences* currentNode = prefs; + auto gradientBackgroundColors = renderWindowWidget.second->GetGradientBackgroundColors(); + preferences->Put(widgetName + " first background color", MitkColorToHex(gradientBackgroundColors.first)); + preferences->Put(widgetName + " second background color", MitkColorToHex(gradientBackgroundColors.second)); - while(currentNode) - { - bool logoFound = false; - foreach (const QString& key, currentNode->Keys()) - { - if( key == "DepartmentLogo") - { - QString departmentLogoLocation = currentNode->Get("DepartmentLogo", ""); - - if (departmentLogoLocation.isEmpty()) - { - d->m_StdMultiWidget->DisableDepartmentLogo(); - } - else - { - // we need to disable the logo first, otherwise setting a new logo will have - // no effect due to how mitkManufacturerLogo works... - d->m_StdMultiWidget->DisableDepartmentLogo(); - d->m_StdMultiWidget->SetDepartmentLogo(qPrintable(departmentLogoLocation)); - d->m_StdMultiWidget->EnableDepartmentLogo(); - } - logoFound = true; - break; - } - } + auto decorationColor = renderWindowWidget.second->GetDecorationColor(); + preferences->Put(widgetName + " decoration color", MitkColorToHex(decorationColor)); + + auto cornerAnnotation = renderWindowWidget.second->GetCornerAnnotationText(); + preferences->Put(widgetName + " corner annotation", QString::fromStdString(cornerAnnotation)); - if (logoFound) break; - currentNode = currentNode->Parent().GetPointer(); + ++i; } +} - //Update internal members - this->FillMembersWithCurrentDecorations(); - this->GetPreferenceDecorations(prefs); - //Now the members can be used to modify the stdmultiwidget - mitk::Color upper = HexColorToMitkColor(d->m_WidgetBackgroundColor1[0]); - mitk::Color lower = HexColorToMitkColor(d->m_WidgetBackgroundColor2[0]); - d->m_StdMultiWidget->SetGradientBackgroundColorForRenderWindow(upper, lower, 0); - upper = HexColorToMitkColor(d->m_WidgetBackgroundColor1[1]); - lower = HexColorToMitkColor(d->m_WidgetBackgroundColor2[1]); - d->m_StdMultiWidget->SetGradientBackgroundColorForRenderWindow(upper, lower, 1); - upper = HexColorToMitkColor(d->m_WidgetBackgroundColor1[2]); - lower = HexColorToMitkColor(d->m_WidgetBackgroundColor2[2]); - d->m_StdMultiWidget->SetGradientBackgroundColorForRenderWindow(upper, lower, 2); - upper = HexColorToMitkColor(d->m_WidgetBackgroundColor1[3]); - lower = HexColorToMitkColor(d->m_WidgetBackgroundColor2[3]); - d->m_StdMultiWidget->SetGradientBackgroundColorForRenderWindow(upper, lower, 3); - d->m_StdMultiWidget->EnableGradientBackground(); - - // preferences for renderWindows - mitk::Color colorDecorationWidget1 = HexColorToMitkColor(d->m_WidgetDecorationColor[0]); - mitk::Color colorDecorationWidget2 = HexColorToMitkColor(d->m_WidgetDecorationColor[1]); - mitk::Color colorDecorationWidget3 = HexColorToMitkColor(d->m_WidgetDecorationColor[2]); - mitk::Color colorDecorationWidget4 = HexColorToMitkColor(d->m_WidgetDecorationColor[3]); - d->m_StdMultiWidget->SetDecorationColor(0, colorDecorationWidget1); - d->m_StdMultiWidget->SetDecorationColor(1, colorDecorationWidget2); - d->m_StdMultiWidget->SetDecorationColor(2, colorDecorationWidget3); - d->m_StdMultiWidget->SetDecorationColor(3, colorDecorationWidget4); - - for(unsigned int i = 0; i < 4; ++i) +void QmitkStdMultiWidgetEditor::GetPreferenceDecorations(const berry::IBerryPreferences * preferences) +{ + auto multiWidget = dynamic_cast(GetMultiWidget()); + if (nullptr == multiWidget) { - d->m_StdMultiWidget->SetDecorationProperties(d->m_WidgetAnnotation[i].toStdString(), - HexColorToMitkColor(d->m_WidgetDecorationColor[i]), i); + return; } - //The crosshair gap - int crosshairgapsize = prefs->GetInt("crosshair gap size", 32); - d->m_StdMultiWidget->GetWidgetPlane1()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); - d->m_StdMultiWidget->GetWidgetPlane2()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); - d->m_StdMultiWidget->GetWidgetPlane3()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); - //refresh colors of rectangles - d->m_StdMultiWidget->EnableColoredRectangles(); + auto hexBlack = "#000000"; + auto gradientBlack = "#191919"; + auto gradientGray = "#7F7F7F"; - // Set preferences respecting zooming and panning - bool constrainedZooming = prefs->GetBool("Use constrained zooming and panning", true); - - mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); + auto renderWindowWidgets = multiWidget->GetRenderWindowWidgets(); + int i = 0; + for (const auto& renderWindowWidget : renderWindowWidgets) + { + QString widgetName = renderWindowWidget.second->GetWidgetName(); - mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); + if (mitk::BaseRenderer::Standard3D == mitk::BaseRenderer::GetInstance(renderWindowWidget.second->GetRenderWindow()->GetVtkRenderWindow())->GetMapperID()) + { + auto upper = preferences->Get(widgetName + " first background color", gradientBlack); + auto lower = preferences->Get(widgetName + " second background color", gradientGray); + renderWindowWidget.second->SetGradientBackgroundColors(HexColorToMitkColor(upper), HexColorToMitkColor(lower)); + } + else + { + auto upper = preferences->Get(widgetName + " first background color", hexBlack); + auto lower = preferences->Get(widgetName + " second background color", hexBlack); + renderWindowWidget.second->SetGradientBackgroundColors(HexColorToMitkColor(upper), HexColorToMitkColor(lower)); + } - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + auto defaultDecorationColor = multiWidget->GetDecorationColor(i); + auto decorationColor = preferences->Get(widgetName + " decoration color", MitkColorToHex(defaultDecorationColor)); + renderWindowWidget.second->SetDecorationColor(HexColorToMitkColor(decorationColor)); + + auto defaultCornerAnnotation = renderWindowWidget.second->GetCornerAnnotationText(); + auto cornerAnnotation = preferences->Get(widgetName + " corner annotation", QString::fromStdString(defaultCornerAnnotation)); + renderWindowWidget.second->SetCornerAnnotationText(cornerAnnotation.toStdString()); - // level window setting - bool showLevelWindowWidget = prefs->GetBool("Show level/window widget", true); - if (showLevelWindowWidget) - { - d->m_StdMultiWidget->EnableStandardLevelWindow(); + ++i; } - else - { - d->m_StdMultiWidget->DisableStandardLevelWindow(); - } - - // mouse modes toolbar - bool newMode = prefs->GetBool("PACS like mouse interaction", false); - d->m_MouseModeToolbar->setVisible( newMode ); - d->m_StdMultiWidget->GetMouseModeSwitcher()->SetInteractionScheme( newMode ? mitk::MouseModeSwitcher::PACS : mitk::MouseModeSwitcher::MITK ); } -mitk::Color QmitkStdMultiWidgetEditor::HexColorToMitkColor(const QString& widgetColorInHex) +mitk::Color QmitkStdMultiWidgetEditor::HexColorToMitkColor(const QString& hexColor) { - QColor qColor(widgetColorInHex); + QColor qColor(hexColor); mitk::Color returnColor; float colorMax = 255.0f; - if (widgetColorInHex.isEmpty()) // default value + if (hexColor.isEmpty()) // default value { returnColor[0] = 1.0; returnColor[1] = 1.0; returnColor[2] = 1.0; - MITK_ERROR << "Using default color for unknown widget " << qPrintable(widgetColorInHex); + MITK_ERROR << "Using default color for unknown hex color " << qPrintable(hexColor); } else { returnColor[0] = qColor.red() / colorMax; returnColor[1] = qColor.green() / colorMax; returnColor[2] = qColor.blue() / colorMax; } return returnColor; } QString QmitkStdMultiWidgetEditor::MitkColorToHex(const mitk::Color& color) { QColor returnColor; float colorMax = 255.0f; - returnColor.setRed(static_cast(color[0]* colorMax + 0.5)); - returnColor.setGreen(static_cast(color[1]* colorMax + 0.5)); - returnColor.setBlue(static_cast(color[2]* colorMax + 0.5)); + returnColor.setRed(static_cast(color[0] * colorMax + 0.5)); + returnColor.setGreen(static_cast(color[1] * colorMax + 0.5)); + returnColor.setBlue(static_cast(color[2] * colorMax + 0.5)); return returnColor.name(); } - -void QmitkStdMultiWidgetEditor::FillMembersWithCurrentDecorations() -{ - //fill members with current values (or default values) from the std multi widget - for(unsigned int i = 0; i < 4; ++i) - { - d->m_WidgetDecorationColor[i] = MitkColorToHex(d->m_StdMultiWidget->GetDecorationColor(i)); - d->m_WidgetBackgroundColor1[i] = MitkColorToHex(d->m_StdMultiWidget->GetGradientColors(i).first); - d->m_WidgetBackgroundColor2[i] = MitkColorToHex(d->m_StdMultiWidget->GetGradientColors(i).second); - d->m_WidgetAnnotation[i] = QString::fromStdString(d->m_StdMultiWidget->GetCornerAnnotationText(i)); - } -} - -void QmitkStdMultiWidgetEditor::GetPreferenceDecorations(const berry::IBerryPreferences * preferences) -{ - //overwrite members with values from the preferences, if they the prefrence is defined - d->m_WidgetBackgroundColor1[0] = preferences->Get("widget1 first background color", d->m_WidgetBackgroundColor1[0]); - d->m_WidgetBackgroundColor2[0] = preferences->Get("widget1 second background color", d->m_WidgetBackgroundColor2[0]); - d->m_WidgetBackgroundColor1[1] = preferences->Get("widget2 first background color", d->m_WidgetBackgroundColor1[1]); - d->m_WidgetBackgroundColor2[1] = preferences->Get("widget2 second background color", d->m_WidgetBackgroundColor2[1]); - d->m_WidgetBackgroundColor1[2] = preferences->Get("widget3 first background color", d->m_WidgetBackgroundColor1[2]); - d->m_WidgetBackgroundColor2[2] = preferences->Get("widget3 second background color", d->m_WidgetBackgroundColor2[2]); - d->m_WidgetBackgroundColor1[3] = preferences->Get("widget4 first background color", d->m_WidgetBackgroundColor1[3]); - d->m_WidgetBackgroundColor2[3] = preferences->Get("widget4 second background color", d->m_WidgetBackgroundColor2[3]); - - d->m_WidgetDecorationColor[0] = preferences->Get("widget1 decoration color", d->m_WidgetDecorationColor[0]); - d->m_WidgetDecorationColor[1] = preferences->Get("widget2 decoration color", d->m_WidgetDecorationColor[1]); - d->m_WidgetDecorationColor[2] = preferences->Get("widget3 decoration color", d->m_WidgetDecorationColor[2]); - d->m_WidgetDecorationColor[3] = preferences->Get("widget4 decoration color", d->m_WidgetDecorationColor[3]); - - d->m_WidgetAnnotation[0] = preferences->Get("widget1 corner annotation", d->m_WidgetAnnotation[0]); - d->m_WidgetAnnotation[1] = preferences->Get("widget2 corner annotation", d->m_WidgetAnnotation[1]); - d->m_WidgetAnnotation[2] = preferences->Get("widget3 corner annotation", d->m_WidgetAnnotation[2]); - d->m_WidgetAnnotation[3] = preferences->Get("widget4 corner annotation", d->m_WidgetAnnotation[3]); -} - -void QmitkStdMultiWidgetEditor::InitializePreferences(berry::IBerryPreferences * preferences) -{ - this->FillMembersWithCurrentDecorations(); //fill members - this->GetPreferenceDecorations(preferences); //overwrite if preferences are defined - - //create new preferences - preferences->Put("widget1 corner annotation", d->m_WidgetAnnotation[0]); - preferences->Put("widget2 corner annotation", d->m_WidgetAnnotation[1]); - preferences->Put("widget3 corner annotation", d->m_WidgetAnnotation[2]); - preferences->Put("widget4 corner annotation", d->m_WidgetAnnotation[3]); - - preferences->Put("widget1 decoration color", d->m_WidgetDecorationColor[0]); - preferences->Put("widget2 decoration color", d->m_WidgetDecorationColor[1]); - preferences->Put("widget3 decoration color", d->m_WidgetDecorationColor[2]); - preferences->Put("widget4 decoration color", d->m_WidgetDecorationColor[3]); - - preferences->Put("widget1 first background color", d->m_WidgetBackgroundColor1[0]); - preferences->Put("widget2 first background color", d->m_WidgetBackgroundColor1[1]); - preferences->Put("widget3 first background color", d->m_WidgetBackgroundColor1[2]); - preferences->Put("widget4 first background color", d->m_WidgetBackgroundColor1[3]); - preferences->Put("widget1 second background color", d->m_WidgetBackgroundColor2[0]); - preferences->Put("widget2 second background color", d->m_WidgetBackgroundColor2[1]); - preferences->Put("widget3 second background color", d->m_WidgetBackgroundColor2[2]); - preferences->Put("widget4 second background color", d->m_WidgetBackgroundColor2[3]); -} - -void QmitkStdMultiWidgetEditor::SetFocus() -{ - if (d->m_StdMultiWidget != nullptr) - d->m_StdMultiWidget->setFocus(); -} - -void QmitkStdMultiWidgetEditor::RequestActivateMenuWidget(bool on) -{ - if (d->m_StdMultiWidget) - { - if (on) - { - d->m_StdMultiWidget->ActivateMenuWidget(d->m_MenuWidgetsEnabled); - } - else - { - d->m_MenuWidgetsEnabled = d->m_StdMultiWidget->IsMenuWidgetEnabled(); - d->m_StdMultiWidget->ActivateMenuWidget(false); - } - } -} - diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h index 9c46ae9539..93ea180ac1 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.h @@ -1,149 +1,129 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QmitkStdMultiWidgetEditor_h -#define QmitkStdMultiWidgetEditor_h +#ifndef QMITKSTDMULTIWIDGETEDITOR_H +#define QMITKSTDMULTIWIDGETEDITOR_H -#include +// mitk gui qt common plugin +#include #include #include +// c++ +#include + class QmitkStdMultiWidget; -class QmitkMouseModeSwitcher; class QmitkStdMultiWidgetEditorPrivate; /** - * \ingroup org_mitk_gui_qt_stdmultiwidgeteditor + * @brief */ -class ORG_MITK_GUI_QT_STDMULTIWIDGETEDITOR QmitkStdMultiWidgetEditor - : public QmitkAbstractRenderEditor, public mitk::ILinkedRenderWindowPart +class ORG_MITK_GUI_QT_STDMULTIWIDGETEDITOR QmitkStdMultiWidgetEditor final : public QmitkAbstractMultiWidgetEditor, + public mitk::ILinkedRenderWindowPart { Q_OBJECT public: - berryObjectMacro(QmitkStdMultiWidgetEditor) - static const QString EDITOR_ID; QmitkStdMultiWidgetEditor(); - ~QmitkStdMultiWidgetEditor() override; - - QmitkStdMultiWidget* GetStdMultiWidget(); - - /// \brief If on=true will request the QmitkStdMultiWidget set the Menu widget to - /// whatever was the last known enabled state, and if on=false will turn the Menu widget off. - void RequestActivateMenuWidget(bool on); - - // ------------------- mitk::IRenderWindowPart ---------------------- + virtual ~QmitkStdMultiWidgetEditor() override; + virtual QmitkLevelWindowWidget* GetLevelWindowWidget() const override; /** - * \see mitk::IRenderWindowPart::GetActiveQmitkRenderWindow() - */ - QmitkRenderWindow* GetActiveQmitkRenderWindow() const override; - - /** - * \see mitk::IRenderWindowPart::GetQmitkRenderWindows() - */ - QHash GetQmitkRenderWindows() const override; - + * @brief Overridden from mitk::ILinkedRenderWindowPart + */ + virtual void EnableSlicingPlanes(bool enable) override; /** - * \see mitk::IRenderWindowPart::GetQmitkRenderWindow(QString) - */ - QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const override; - + * @brief Overridden from mitk::ILinkedRenderWindowPart + */ + virtual bool IsSlicingPlanesEnabled() const override; /** - * \see mitk::IRenderWindowPart::GetSelectionPosition() - */ - mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; - + * @brief Overridden from berry::IPartListener + */ + virtual berry::IPartListener::Events::Types GetPartEventTypes() const override; /** - * \see mitk::IRenderWindowPart::SetSelectedPosition() - */ - void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; - + * @brief Overridden from berry::IPartListener + */ + virtual void PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** - * \see mitk::IRenderWindowPart::EnableDecorations() - */ - void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; - + * @brief Overridden from berry::IPartListener + */ + virtual void PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** - * \see mitk::IRenderWindowPart::IsDecorationEnabled() - */ - bool IsDecorationEnabled(const QString& decoration) const override; - + * @brief Overridden from berry::IPartListener + */ + virtual void PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** - * \see mitk::IRenderWindowPart::GetDecorations() - */ - QStringList GetDecorations() const override; - - // ------------------- mitk::ILinkedRenderWindowPart ---------------------- - - void EnableSlicingPlanes(bool enable) override; - bool IsSlicingPlanesEnabled() const override; + * @brief Overridden from berry::IPartListener + */ + virtual void PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) override; + void OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); -protected: + void ShowLevelWindowWidget(bool show); +private: /** - * @brief FillMembersWithCurrentDecorations Helper method to fill internal members with - * current values of the std multi widget. - */ - void FillMembersWithCurrentDecorations(); - + * @brief Overridden from QmitkAbstractRenderEditor + */ + virtual void SetFocus() override; + /** + * @brief Overridden from QmitkAbstractRenderEditor + */ + virtual void CreateQtPartControl(QWidget* parent) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor + */ + virtual void OnPreferencesChanged(const berry::IBerryPreferences* preferences) override; + /** + * @brief InitializePreferences Internal helper method to set default preferences. + * This method is used to show the current preferences in the first call of + * the preference page (the GUI). + * + * @param preferences berry preferences. + */ + void InitializePreferences(berry::IBerryPreferences *preferences); /** * @brief GetPreferenceDecorations Getter to fill internal members with values of preferences. * @param preferences The berry preferences. * * If a preference is set, the value will overwrite the current value. If it does not exist, * the value will not change. */ void GetPreferenceDecorations(const berry::IBerryPreferences *preferences); - - void SetFocus() override; - - void OnPreferencesChanged(const berry::IBerryPreferences*) override; - - void CreateQtPartControl(QWidget* parent) override; - /** * @brief GetColorForWidget helper method to convert a saved color string to mitk::Color. - * @param widgetColorInHex color in hex format (#12356) where each diget is in the form (0-F). + * @param hexColor color in hex format (#12356) where each digit is in the form (0-F). * @return the color in mitk format. */ - mitk::Color HexColorToMitkColor(const QString& widgetColorInHex); + mitk::Color HexColorToMitkColor(const QString& hexColor); /** * @brief MitkColorToHex Convert an mitk::Color to hex string. * @param color mitk format. * @return String in hex (#RRGGBB). */ QString MitkColorToHex(const mitk::Color& color); - /** - * @brief InitializePreferences Internal helper method to set default preferences. - * This method is used to show the current preferences in the first call of - * the preference page (the GUI). - * - * @param preferences berry preferences. - */ - void InitializePreferences(berry::IBerryPreferences *preferences); + struct Impl; + std::unique_ptr m_Impl; -private: - const QScopedPointer d; }; -#endif /*QmitkStdMultiWidgetEditor_h*/ + +#endif // QMITKSTDMULTIWIDGETEDITOR_H diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp index 3798d40cdd..fc8faedc73 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp @@ -1,263 +1,263 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "QmitkStdMultiWidgetEditorPreferencePage.h" #include #include #include #include QmitkStdMultiWidgetEditorPreferencePage::QmitkStdMultiWidgetEditorPreferencePage() : m_Preferences(nullptr), m_Ui(new Ui::QmitkStdMultiWidgetEditorPreferencePage), m_Control(nullptr) { } QmitkStdMultiWidgetEditorPreferencePage::~QmitkStdMultiWidgetEditorPreferencePage() { } void QmitkStdMultiWidgetEditorPreferencePage::CreateQtControl(QWidget* parent) { m_Control = new QWidget(parent); m_Ui->setupUi(m_Control); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); Q_ASSERT(prefService); m_Preferences = prefService->GetSystemPreferences()->Node(QmitkStdMultiWidgetEditor::EDITOR_ID); QObject::connect( m_Ui->m_ColorButton1, SIGNAL( clicked() ) , this, SLOT( ColorChooserButtonClicked() ) ); QObject::connect( m_Ui->m_ColorButton2, SIGNAL( clicked() ) , this, SLOT( ColorChooserButtonClicked() ) ); QObject::connect( m_Ui->m_ResetButton, SIGNAL( clicked() ) , this, SLOT( ResetPreferencesAndGUI() ) ); QObject::connect( m_Ui->m_RenderingMode, SIGNAL(activated(int) ) , this, SLOT( ChangeRenderingMode(int) ) ); QObject::connect( m_Ui->m_RenderWindowDecorationColor, SIGNAL( clicked() ) , this, SLOT( ColorChooserButtonClicked() ) ); QObject::connect( m_Ui->m_RenderWindowChooser, SIGNAL(activated(int) ) , this, SLOT( OnWidgetComboBoxChanged(int) ) ); QObject::connect( m_Ui->m_RenderWindowDecorationText, SIGNAL(textChanged(QString) ) , this, SLOT( AnnotationTextChanged(QString) ) ); this->Update(); } QWidget* QmitkStdMultiWidgetEditorPreferencePage::GetQtControl() const { return m_Control; } void QmitkStdMultiWidgetEditorPreferencePage::Init(berry::IWorkbench::Pointer) { } void QmitkStdMultiWidgetEditorPreferencePage::PerformCancel() { } bool QmitkStdMultiWidgetEditorPreferencePage::PerformOk() { - m_Preferences->Put("widget1 corner annotation", m_WidgetAnnotation[0]); - m_Preferences->Put("widget2 corner annotation", m_WidgetAnnotation[1]); - m_Preferences->Put("widget3 corner annotation", m_WidgetAnnotation[2]); - m_Preferences->Put("widget4 corner annotation", m_WidgetAnnotation[3]); - - m_Preferences->Put("widget1 decoration color", m_WidgetDecorationColor[0]); - m_Preferences->Put("widget2 decoration color", m_WidgetDecorationColor[1]); - m_Preferences->Put("widget3 decoration color", m_WidgetDecorationColor[2]); - m_Preferences->Put("widget4 decoration color", m_WidgetDecorationColor[3]); - - m_Preferences->Put("widget1 first background color", m_WidgetBackgroundColor1[0]); - m_Preferences->Put("widget2 first background color", m_WidgetBackgroundColor1[1]); - m_Preferences->Put("widget3 first background color", m_WidgetBackgroundColor1[2]); - m_Preferences->Put("widget4 first background color", m_WidgetBackgroundColor1[3]); - m_Preferences->Put("widget1 second background color", m_WidgetBackgroundColor2[0]); - m_Preferences->Put("widget2 second background color", m_WidgetBackgroundColor2[1]); - m_Preferences->Put("widget3 second background color", m_WidgetBackgroundColor2[2]); - m_Preferences->Put("widget4 second background color", m_WidgetBackgroundColor2[3]); + m_Preferences->Put("stdmulti.widget0 corner annotation", m_WidgetAnnotation[0]); + m_Preferences->Put("stdmulti.widget1 corner annotation", m_WidgetAnnotation[1]); + m_Preferences->Put("stdmulti.widget2 corner annotation", m_WidgetAnnotation[2]); + m_Preferences->Put("stdmulti.widget3 corner annotation", m_WidgetAnnotation[3]); + + m_Preferences->Put("stdmulti.widget0 decoration color", m_WidgetDecorationColor[0]); + m_Preferences->Put("stdmulti.widget1 decoration color", m_WidgetDecorationColor[1]); + m_Preferences->Put("stdmulti.widget2 decoration color", m_WidgetDecorationColor[2]); + m_Preferences->Put("stdmulti.widget3 decoration color", m_WidgetDecorationColor[3]); + + m_Preferences->Put("stdmulti.widget0 first background color", m_WidgetBackgroundColor1[0]); + m_Preferences->Put("stdmulti.widget1 first background color", m_WidgetBackgroundColor1[1]); + m_Preferences->Put("stdmulti.widget2 first background color", m_WidgetBackgroundColor1[2]); + m_Preferences->Put("stdmulti.widget3 first background color", m_WidgetBackgroundColor1[3]); + m_Preferences->Put("stdmulti.widget0 second background color", m_WidgetBackgroundColor2[0]); + m_Preferences->Put("stdmulti.widget1 second background color", m_WidgetBackgroundColor2[1]); + m_Preferences->Put("stdmulti.widget2 second background color", m_WidgetBackgroundColor2[2]); + m_Preferences->Put("stdmulti.widget3 second background color", m_WidgetBackgroundColor2[3]); m_Preferences->PutInt("crosshair gap size", m_Ui->m_CrosshairGapSize->value()); m_Preferences->PutBool("Use constrained zooming and panning" , m_Ui->m_EnableFlexibleZooming->isChecked()); m_Preferences->PutBool("Show level/window widget", m_Ui->m_ShowLevelWindowWidget->isChecked()); m_Preferences->PutBool("PACS like mouse interaction", m_Ui->m_PACSLikeMouseMode->isChecked()); m_Preferences->PutInt("Rendering Mode", m_Ui->m_RenderingMode->currentIndex()); return true; } void QmitkStdMultiWidgetEditorPreferencePage::Update() { //Note: there should be default preferences already defined in the //QmitkStdMultiWidgetEditor::InitializePreferences(). Therefore, //all default values here are not relevant. //gradient background colors - m_WidgetBackgroundColor1[0] = m_Preferences->Get("widget1 first background color", "#1d1d1c"); - m_WidgetBackgroundColor2[0] = m_Preferences->Get("widget1 second background color", "#1d1d1c"); - m_WidgetBackgroundColor1[1] = m_Preferences->Get("widget2 first background color", "#1d1d1c"); - m_WidgetBackgroundColor2[1] = m_Preferences->Get("widget2 second background color", "#1d1d1c"); - m_WidgetBackgroundColor1[2] = m_Preferences->Get("widget3 first background color", "#1d1d1c"); - m_WidgetBackgroundColor2[2] = m_Preferences->Get("widget3 second background color", "#1d1d1c"); - m_WidgetBackgroundColor1[3] = m_Preferences->Get("widget4 first background color", "#1d1d1c"); - m_WidgetBackgroundColor2[3] = m_Preferences->Get("widget4 second background color", "#adb1b6"); + m_WidgetBackgroundColor1[0] = m_Preferences->Get("stdmulti.widget0 first background color", "#1d1d1c"); + m_WidgetBackgroundColor2[0] = m_Preferences->Get("stdmulti.widget0 second background color", "#1d1d1c"); + m_WidgetBackgroundColor1[1] = m_Preferences->Get("stdmulti.widget1 first background color", "#1d1d1c"); + m_WidgetBackgroundColor2[1] = m_Preferences->Get("stdmulti.widget1 second background color", "#1d1d1c"); + m_WidgetBackgroundColor1[2] = m_Preferences->Get("stdmulti.widget2 first background color", "#1d1d1c"); + m_WidgetBackgroundColor2[2] = m_Preferences->Get("stdmulti.widget2 second background color", "#1d1d1c"); + m_WidgetBackgroundColor1[3] = m_Preferences->Get("stdmulti.widget3 first background color", "#1d1d1c"); + m_WidgetBackgroundColor2[3] = m_Preferences->Get("stdmulti.widget3 second background color", "#adb1b6"); //decoration colors - m_WidgetDecorationColor[0] = m_Preferences->Get("widget1 decoration color", "#c00000"); - m_WidgetDecorationColor[1] = m_Preferences->Get("widget2 decoration color", "#0fad00"); - m_WidgetDecorationColor[2] = m_Preferences->Get("widget3 decoration color", "#0080ff"); - m_WidgetDecorationColor[3] = m_Preferences->Get("widget4 decoration color", "#fec500"); + m_WidgetDecorationColor[0] = m_Preferences->Get("stdmulti.widget0 decoration color", "#c00000"); + m_WidgetDecorationColor[1] = m_Preferences->Get("stdmulti.widget1 decoration color", "#0fad00"); + m_WidgetDecorationColor[2] = m_Preferences->Get("stdmulti.widget2 decoration color", "#0080ff"); + m_WidgetDecorationColor[3] = m_Preferences->Get("stdmulti.widget3 decoration color", "#fec500"); //annotation text - m_WidgetAnnotation[0] = m_Preferences->Get("widget1 corner annotation", "Axial"); - m_WidgetAnnotation[1] = m_Preferences->Get("widget2 corner annotation", "Sagittal"); - m_WidgetAnnotation[2] = m_Preferences->Get("widget3 corner annotation", "Coronal"); - m_WidgetAnnotation[3] = m_Preferences->Get("widget4 corner annotation", "3D"); + m_WidgetAnnotation[0] = m_Preferences->Get("stdmulti.widget0 corner annotation", "Axial"); + m_WidgetAnnotation[1] = m_Preferences->Get("stdmulti.widget1 corner annotation", "Sagittal"); + m_WidgetAnnotation[2] = m_Preferences->Get("stdmulti.widget2 corner annotation", "Coronal"); + m_WidgetAnnotation[3] = m_Preferences->Get("stdmulti.widget3 corner annotation", "3D"); //Ui stuff int index = m_Ui->m_RenderWindowChooser->currentIndex(); QColor firstBackgroundColor(m_WidgetBackgroundColor1[index]); QColor secondBackgroundColor(m_WidgetBackgroundColor2[index]); QColor widgetColor(m_WidgetDecorationColor[index]); this->SetStyleSheetToColorChooserButton(firstBackgroundColor, m_Ui->m_ColorButton1); this->SetStyleSheetToColorChooserButton(secondBackgroundColor, m_Ui->m_ColorButton2); this->SetStyleSheetToColorChooserButton(widgetColor, m_Ui->m_RenderWindowDecorationColor); m_Ui->m_RenderWindowDecorationText->setText(m_WidgetAnnotation[index]); m_Ui->m_EnableFlexibleZooming->setChecked(m_Preferences->GetBool("Use constrained zooming and panning", true)); m_Ui->m_ShowLevelWindowWidget->setChecked(m_Preferences->GetBool("Show level/window widget", true)); m_Ui->m_PACSLikeMouseMode->setChecked(m_Preferences->GetBool("PACS like mouse interaction", false)); int mode= m_Preferences->GetInt("Rendering Mode",0); m_Ui->m_RenderingMode->setCurrentIndex(mode); m_Ui->m_CrosshairGapSize->setValue(m_Preferences->GetInt("crosshair gap size", 32)); } void QmitkStdMultiWidgetEditorPreferencePage::ColorChooserButtonClicked() { unsigned int widgetIndex = m_Ui->m_RenderWindowChooser->currentIndex(); if(widgetIndex > 3) { MITK_ERROR << "Selected index for unknown."; return; } QObject *senderObj = sender(); // This will give Sender button //find out last used color and set it QColor initialColor; if( senderObj->objectName() == m_Ui->m_ColorButton1->objectName()) { initialColor = QColor(m_WidgetBackgroundColor1[widgetIndex]); }else if( senderObj->objectName() == m_Ui->m_ColorButton2->objectName()) { initialColor = QColor(m_WidgetBackgroundColor2[widgetIndex]); }else if( senderObj->objectName() == m_Ui->m_RenderWindowDecorationColor->objectName()) { initialColor = QColor(m_WidgetDecorationColor[widgetIndex]); } //get the new color QColor newcolor = QColorDialog::getColor(initialColor); if(!newcolor.isValid()) { newcolor = initialColor; } this->SetStyleSheetToColorChooserButton(newcolor, static_cast(senderObj)); //convert it to std string and apply it if( senderObj->objectName() == m_Ui->m_ColorButton1->objectName()) { m_WidgetBackgroundColor1[widgetIndex] = newcolor.name(); } else if( senderObj->objectName() == m_Ui->m_ColorButton2->objectName()) { m_WidgetBackgroundColor2[widgetIndex] = newcolor.name(); } else if( senderObj->objectName() == m_Ui->m_RenderWindowDecorationColor->objectName()) { m_WidgetDecorationColor[widgetIndex] = newcolor.name(); } } void QmitkStdMultiWidgetEditorPreferencePage::SetStyleSheetToColorChooserButton(QColor backgroundcolor, QPushButton* button) { button->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(backgroundcolor.red())); styleSheet.append(","); styleSheet.append(QString::number(backgroundcolor.green())); styleSheet.append(","); styleSheet.append(QString::number(backgroundcolor.blue())); styleSheet.append(")"); button->setStyleSheet(styleSheet); } void QmitkStdMultiWidgetEditorPreferencePage::AnnotationTextChanged(QString text) { unsigned int widgetIndex = m_Ui->m_RenderWindowChooser->currentIndex(); if( widgetIndex > 3) { MITK_INFO << "Selected index for unknown widget."; return; } m_WidgetAnnotation[widgetIndex] = text; } void QmitkStdMultiWidgetEditorPreferencePage::ResetPreferencesAndGUI() { m_Preferences->Clear(); this->Update(); } void QmitkStdMultiWidgetEditorPreferencePage::OnWidgetComboBoxChanged(int i) { if( i > 3) { MITK_ERROR << "Selected unknown widget."; return; } QColor widgetColor(m_WidgetDecorationColor[i]); QColor gradientBackground1(m_WidgetBackgroundColor1[i]); QColor gradientBackground2(m_WidgetBackgroundColor2[i]); this->SetStyleSheetToColorChooserButton(widgetColor, m_Ui->m_RenderWindowDecorationColor); this->SetStyleSheetToColorChooserButton(gradientBackground1, m_Ui->m_ColorButton1); this->SetStyleSheetToColorChooserButton(gradientBackground2, m_Ui->m_ColorButton2); m_Ui->m_RenderWindowDecorationText->setText(m_WidgetAnnotation[i]); } void QmitkStdMultiWidgetEditorPreferencePage::ChangeRenderingMode(int ) { //if( i == 0 ) //{ m_CurrentRenderingMode = "Standard"; //} }