diff --git a/Modules/Core/include/mitkDisplayInteractor.h b/Modules/Core/include/mitkDisplayInteractor.h index 5be2331035..cfe03302be 100644 --- a/Modules/Core/include/mitkDisplayInteractor.h +++ b/Modules/Core/include/mitkDisplayInteractor.h @@ -1,276 +1,275 @@ /*=================================================================== 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 mitkDisplayInteractor_h #define mitkDisplayInteractor_h #include "mitkInteractionEventObserver.h" #include namespace mitk { /** *\class DisplayInteractor *@brief Observer that manages the interaction with the display. * * This includes the interaction of Zooming, Panning, Scrolling and adjusting the LevelWindow. * * @ingroup Interaction **/ /** * Inherits from mitk::InteractionEventObserver since it doesn't alter any data (only their representation), * and its actions cannot be associated with a DataNode. Also inherits from EventStateMachine */ class MITKCORE_EXPORT DisplayInteractor : public EventStateMachine, public InteractionEventObserver { public: - mitkClassMacro(DisplayInteractor, EventStateMachine) itkFactorylessNewMacro(Self) itkCloneMacro(Self) - /** - * By this function the Observer gets notified about new events. - * Here it is adapted to pass the events to the state machine in order to use - * its infrastructure. - * It also checks if event is to be accepted when it already has been processed by a DataInteractor. - */ - virtual void Notify(InteractionEvent *interactionEvent, bool isHandled) override; + mitkClassMacro(DisplayInteractor, EventStateMachine) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + /** + * By this function the Observer gets notified about new events. + * Here it is adapted to pass the events to the state machine in order to use + * its infrastructure. + * It also checks if event is to be accepted when it already has been processed by a DataInteractor. + */ + virtual void Notify(InteractionEvent *interactionEvent, bool isHandled) override; protected: DisplayInteractor(); virtual ~DisplayInteractor(); /** * Derived function. * Connects the action names used in the state machine pattern with functions implemented within * this InteractionEventObserver. This is only necessary here because the events are processed by the state machine. */ void ConnectActionsAndFunctions() override; /** * Derived function. * Is executed when config object is set / changed. * Here it is used to read out the parameters set in the configuration file, * and set the member variables accordingly. */ virtual void ConfigurationChanged() override; /** * Derived function. * Is executed when config object is set / changed. * Here it is used to read out the parameters set in the configuration file, * and set the member variables accordingly. */ virtual bool FilterEvents(InteractionEvent *interactionEvent, DataNode *dataNode) override; virtual bool CheckPositionEvent(const InteractionEvent *interactionEvent); virtual bool CheckRotationPossible(const InteractionEvent *interactionEvent); virtual bool CheckSwivelPossible(const InteractionEvent *interactionEvent); /** * \brief Initializes an interaction, saves the pointers start position for further reference. */ virtual void Init(StateMachineAction *, InteractionEvent *); /** * \brief Performs panning of the data set in the render window. */ virtual void Move(StateMachineAction *, InteractionEvent *); /** * \brief Sets crosshair at clicked position* */ virtual void SetCrosshair(StateMachineAction *, InteractionEvent *); /** * \brief Performs zooming relative to mouse/pointer movement. * * Behavior is determined by \see m_ZoomDirection and \see m_ZoomFactor. * */ virtual void Zoom(StateMachineAction *, InteractionEvent *); /** * \brief Performs scrolling relative to mouse/pointer movement. * * Behavior is determined by \see m_ScrollDirection and \see m_AutoRepeat. * */ virtual void Scroll(StateMachineAction *, InteractionEvent *); /** * \brief Scrolls one layer up */ virtual void ScrollOneDown(StateMachineAction *, InteractionEvent *); /** * \brief Scrolls one layer down */ virtual void ScrollOneUp(StateMachineAction *, InteractionEvent *); /** * \brief Adjusts the level windows relative to mouse/pointer movement. */ virtual void AdjustLevelWindow(StateMachineAction *, InteractionEvent *); /** * \brief Starts crosshair rotation */ virtual void StartRotation(StateMachineAction *, InteractionEvent *); /** * \brief Ends crosshair rotation */ virtual void EndRotation(StateMachineAction *, InteractionEvent *); /** * \brief */ virtual void Rotate(StateMachineAction *, InteractionEvent *event); virtual void Swivel(StateMachineAction *, InteractionEvent *event); /** * \brief Updates the Statusbar information with the information about the clicked position */ virtual void UpdateStatusbar(StateMachineAction *, InteractionEvent *event); /** * \brief Method to retrieve bool-value for given property from string-property * in given propertylist. */ bool GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char *propertyName, bool defaultValue); - // Typedefs - typedef std::vector SNCVector; - private: mitk::DataNode::Pointer GetTopLayerNode(mitk::DataStorage::SetOfObjects::ConstPointer nodes, mitk::Point3D worldposition, BaseRenderer *ren); /** * @brief UpdateStatusBar * @param image3D * @param idx * @param time * @param component If the PixelType of image3D is a vector (for example a 2D velocity vector), then only one of the vector components can be * displayed at once. Setting this parameter will determine which of the vector's components will be used to determine the displayed PixelValue. * Set this to 0 for scalar images */ void UpdateStatusBar(itk::SmartPointer image3D, itk::Index<3> idx, TimeStepType time=0, int component=0); /** * \brief Coordinate of the pointer at begin of an interaction translated to mm unit */ mitk::Point2D m_StartCoordinateInMM; /** * \brief Coordinate of the pointer in the last step within an interaction. */ mitk::Point2D m_LastDisplayCoordinate; /** * \brief Coordinate of the pointer in the last step within an interaction translated to mm unit */ mitk::Point2D m_LastCoordinateInMM; /** * \brief Current coordinates of the pointer. */ mitk::Point2D m_CurrentDisplayCoordinate; /** * \brief Modifier that defines how many slices are scrolled per pixel that the mouse has moved * * This modifier defines how many slices the scene is scrolled per pixel that the mouse cursor has 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; /** Defines behavior at end of data set. * If set to true it will restart at end of data set from the beginning. */ bool m_AutoRepeat; /** * Defines scroll behavior. * Default is up/down movement of pointer performs scrolling */ std::string m_ScrollDirection; /** * Defines how the axis of interaction influences scroll behavior. */ bool m_InvertScrollDirection; /** * Defines scroll behavior. * Default is up/down movement of pointer performs zooming */ std::string m_ZoomDirection; /** * Defines how the axis of interaction influences zoom behavior. */ bool m_InvertZoomDirection; /** * Defines how the axis of interaction influences move behavior. */ bool m_InvertMoveDirection; /** * Defines level/window behavior. * Default is left/right movement of pointer modifies the level. */ std::string m_LevelDirection; /** * Defines how the axis of interaction influences level/window behavior. */ bool m_InvertLevelWindowDirection; /** * Determines if the Observer reacts to events that already have been processed by a DataInteractor. * The default value is false. */ bool m_AlwaysReact; /** * Factor to adjust zooming speed. */ float m_ZoomFactor; ///// Members to deal with rotating slices /** * @brief m_LinkPlanes Determines if angle between crosshair remains fixed when rotating */ bool m_LinkPlanes; + typedef std::vector SNCVector; SNCVector m_RotatableSNCs; /// all SNCs that currently have CreatedWorldGeometries, that can be rotated. - SNCVector - m_SNCsToBeRotated; /// all SNCs that will be rotated (exceptions are the ones parallel to the one being clicked) + SNCVector m_SNCsToBeRotated; /// all SNCs that will be rotated (exceptions are the ones parallel to the one being clicked) Point3D m_LastCursorPosition; /// used for calculation of the rotation angle Point3D m_CenterOfRotation; /// used for calculation of the rotation angle Point2D m_ReferenceCursor; Vector3D m_RotationPlaneNormal; Vector3D m_RotationPlaneXVector; Vector3D m_RotationPlaneYVector; Vector3D m_PreviousRotationAxis; ScalarType m_PreviousRotationAngle; }; } #endif diff --git a/Modules/QtWidgets/include/QmitkCustomMultiWidget.h b/Modules/QtWidgets/include/QmitkCustomMultiWidget.h index 9e49fbdd66..560335993f 100644 --- a/Modules/QtWidgets/include/QmitkCustomMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkCustomMultiWidget.h @@ -1,217 +1,217 @@ /*=================================================================== 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 QMITKCUSTOMMULTIWIDGET_H #define QMITKCUSTOMMULTIWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include #include // qt #include class QHBoxLayout; class QVBoxLayout; class QGridLayout; class QSpacerItem; class QmitkLevelWindowWidget; class QmitkRenderWindow; class vtkCornerAnnotation; namespace mitk { class RenderingManager; } /** * @brief The 'QmitkCustomMultiWidget' is a 'QWidget' 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. */ class MITKQTWIDGETS_EXPORT QmitkCustomMultiWidget : public QWidget { Q_OBJECT public: QmitkCustomMultiWidget(QWidget* parent = 0, Qt::WindowFlags f = 0, mitk::RenderingManager* renderingManager = nullptr, mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, const QString& multiWidgetName = "custommulti"); virtual ~QmitkCustomMultiWidget(); void SetDataStorage(mitk::DataStorage* dataStorage); void InitRenderWindowWidgets(); using RenderWindowWidgetMap = std::map; using RenderWindowHash = QHash; RenderWindowWidgetMap GetRenderWindowWidgets() const; QmitkRenderWindowWidget* GetRenderWindowWidget(const QString& widgetID) const; QmitkRenderWindow* GetRenderWindow(const QString& widgetID) const; QmitkRenderWindowWidget* GetActiveRenderWindowWidget() const; QmitkRenderWindowWidget* GetFirstRenderWindowWidget() const; QmitkRenderWindowWidget* GetLastRenderWindowWidget() const; unsigned int GetNumberOfRenderWindowWidgets() const; void RequestUpdate(const QString& widgetID); void RequestUpdateAll(); void ForceImmediateUpdate(const QString& widgetID); void ForceImmediateUpdateAll(); mitk::MouseModeSwitcher* GetMouseModeSwitcher(); const mitk::Point3D GetCrossPosition(const QString& widgetID) const; public slots: void ShowLevelWindowWidget(const QString& widgetID, bool show); void ShowAllLevelWindowWidgets(bool show); /** * @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 SetBackgroundColorGradient(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. */ // #TODO: 'backgroundgradientcolor' void SetAllBackgroundColorGradients(const mitk::Color& upper, const mitk::Color& lower); void FillAllBackgroundColorGradientsWithBlack(); void ShowBackgroundColorGradient(const QString& widgetID, bool show); void ShowAllBackgroundColorGradients(bool show); /** * @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 GetBackgroundColorGradient(const QString& widgetID) const; bool GetBackgroundColorGradientFlag(const QString& widgetID) const; void SetDepartmentLogoPath(const char* path); void ShowDepartmentLogo(const QString& widgetID, bool show); void ShowAllDepartmentLogos(bool show); void SetDecorationColor(const QString& widgetID, 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; void ShowCornerAnnotation(const QString& widgetID, bool show); void ShowAllCornerAnnotations(bool show); bool IsCornerAnnotationVisible(const QString& widgetID) const; void SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation); std::string GetCornerAnnotationText(const QString& widgetID) const; /** * @brief Listener to the CrosshairPositionEvent * * Ensures the CrosshairPositionEvent is handled only once and at the end of the Qt-Event loop */ void HandleCrosshairPositionEvent(); /** * @brief Receives the signal from HandleCrosshairPositionEvent, executes the StatusBar update * */ void HandleCrosshairPositionEventDelayed(); void Fit(); void EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p); void MoveCrossToPosition(const QString& widgetID, const mitk::Point3D& newPosition); void ResetCrosshair(); // mouse events void wheelEvent(QWheelEvent* e) override; void mousePressEvent(QMouseEvent* e) override; void moveEvent(QMoveEvent* e) override; signals: void WheelMoved(QWheelEvent *); void Moved(); public: enum { AXIAL, SAGITTAL, CORONAL, THREE_D }; private: void InitializeGUI(); void InitializeWidget(); - void AddRenderWindowWidget(); + void AddRenderWindowWidget(int column, int row, const std::string& cornerAnnotation = ""); // #TODO: see T24173 mitk::DataNode::Pointer GetTopLayerNode(mitk::DataStorage::SetOfObjects::ConstPointer nodes); QGridLayout* m_CustomMultiWidgetLayout; RenderWindowWidgetMap m_RenderWindowWidgets; QmitkRenderWindowWidget* m_ActiveRenderWindowWidget; int m_PlaneMode; mitk::RenderingManager* m_RenderingManager; mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; QString m_MultiWidgetName; mitk::MouseModeSwitcher::Pointer m_MouseModeSwitcher; mitk::SliceNavigationController *m_TimeNavigationController; mitk::DataStorage::Pointer m_DataStorage; bool m_PendingCrosshairPositionEvent; bool m_CrosshairNavigationEnabled; }; #endif // QMITKCUSTOMMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h b/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h index a444f12477..3d7b905fa0 100644 --- a/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h +++ b/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h @@ -1,89 +1,86 @@ /*=================================================================== 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 QmitkMouseModeSwitcher_h #define QmitkMouseModeSwitcher_h #include "MitkQtWidgetsExports.h" #include "mitkMouseModeSwitcher.h" #include #include /** * \ingroup QmitkModule * \brief Qt toolbar representing mitk::MouseModeSwitcher. * * Provides buttons for the interaction modes defined in mitk::MouseModeSwitcher * and communicates with this non-graphical class. * * Can be used in a GUI to provide a mouse mode selector to the user. */ class MITKQTWIDGETS_EXPORT QmitkMouseModeSwitcher : public QToolBar { Q_OBJECT public: - QmitkMouseModeSwitcher(QWidget *parent = 0); + QmitkMouseModeSwitcher(QWidget* parent = nullptr); ~QmitkMouseModeSwitcher() override; typedef mitk::MouseModeSwitcher::MouseMode MouseMode; public slots: /** \brief Connect to non-GUI class. When a button is pressed, given mitk::MouseModeSwitcher is informed to adapt interactors. \todo QmitkMouseModeSwitcher could be enhanced to actively observe mitk::MouseModeSwitcher and change available actions or visibility appropriately. */ - void setMouseModeSwitcher(mitk::MouseModeSwitcher *); + void setMouseModeSwitcher(mitk::MouseModeSwitcher*); signals: /** \brief Mode activated. This signal is needed for other GUI element to react appropriately. Sadly this is needed to provide "normal" functionality of QmitkStdMultiWidget, because this must enable/disable automatic reaction of SliceNavigationControllers to mouse clicks - depending on which mode is active. */ - void MouseModeSelected(mitk::MouseModeSwitcher::MouseMode id); // TODO change int to enum of MouseModeSwitcher + void MouseModeSelected(MouseMode id); protected slots: - void modeSelectedByUser(); - void addButton(MouseMode id, - const QString &toolName, - const QIcon &icon, - bool on = false); // TODO change int to enum of MouseModeSwitcher + void OnMouseModeChangedViaButton(); + void addButton(MouseMode id, const QString& toolName, const QIcon& icon, bool on = false); protected: - void OnMouseModeChanged(const itk::EventObject &); + void OnMouseModeChangedViaCommand(const itk::EventObject&); - QActionGroup *m_ActionGroup; - mitk::MouseModeSwitcher *m_MouseModeSwitcher; + QActionGroup* m_ActionGroup; + mitk::MouseModeSwitcher* m_MouseModeSwitcher; unsigned long m_ObserverTag; - bool m_InObservationReaction; + bool m_ActionButtonBlocked; }; #endif diff --git a/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp b/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp index 7210c243f8..f484b939ad 100644 --- a/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp @@ -1,716 +1,720 @@ /*=================================================================== 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 "QmitkCustomMultiWidget.h" #include #include #include #include #include #include "mitkImagePixelReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt #include QmitkCustomMultiWidget::QmitkCustomMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, mitk::RenderingManager* renderingManager/* = nullptr*/, mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, const QString& multiWidgetName/* = "custommulti"*/) : QWidget(parent, f) , m_CustomMultiWidgetLayout(nullptr) , m_RenderingManager(renderingManager) , m_RenderingMode(renderingMode) , m_MultiWidgetName(multiWidgetName) , m_PendingCrosshairPositionEvent(false) , m_CrosshairNavigationEnabled(false) { // create widget manually // create and set layout InitializeGUI(); resize(QSize(364, 477).expandedTo(minimumSizeHint())); InitializeWidget(); } QmitkCustomMultiWidget::~QmitkCustomMultiWidget() { // nothing here } void QmitkCustomMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->SetDataStorage(m_DataStorage); } } void QmitkCustomMultiWidget::InitRenderWindowWidgets() { // create three render window (widgets) initially - AddRenderWindowWidget(); - AddRenderWindowWidget(); - AddRenderWindowWidget(); + AddRenderWindowWidget(0, 0, "2015-01-14 - CT"); + AddRenderWindowWidget(0, 1, "2015-01-14 - MR"); + AddRenderWindowWidget(1, 0, "2015-08-19 - CT"); + AddRenderWindowWidget(1, 1, "2015-08-19 - MR"); + AddRenderWindowWidget(2, 0, "2016-06-29 - CT"); + AddRenderWindowWidget(2, 1, "2016-06-29 - MR"); } QmitkCustomMultiWidget::RenderWindowWidgetMap QmitkCustomMultiWidget::GetRenderWindowWidgets() const { return m_RenderWindowWidgets; } QmitkRenderWindowWidget* QmitkCustomMultiWidget::GetRenderWindowWidget(const QString& widgetID) const { RenderWindowWidgetMap::const_iterator it = m_RenderWindowWidgets.find(widgetID); if (it == m_RenderWindowWidgets.end()) { return nullptr; } return it->second; } QmitkRenderWindow* QmitkCustomMultiWidget::GetRenderWindow(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetRenderWindow(); } return nullptr; } QmitkRenderWindowWidget* QmitkCustomMultiWidget::GetActiveRenderWindowWidget() const { //return m_ActiveRenderWindowWidget; return m_RenderWindowWidgets.begin()->second; } QmitkRenderWindowWidget* QmitkCustomMultiWidget::GetFirstRenderWindowWidget() const { return m_RenderWindowWidgets.begin()->second; } QmitkRenderWindowWidget* QmitkCustomMultiWidget::GetLastRenderWindowWidget() const { return m_RenderWindowWidgets.rbegin()->second; } unsigned int QmitkCustomMultiWidget::GetNumberOfRenderWindowWidgets() const { return m_RenderWindowWidgets.size(); } void QmitkCustomMultiWidget::RequestUpdate(const QString& widgetID) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->RequestUpdate(); } } void QmitkCustomMultiWidget::RequestUpdateAll() { // #TODO: Update only render windows that show the same image? // #TODO: Update only type specific render windows (2D / 3D)? for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->RequestUpdate(); } } void QmitkCustomMultiWidget::ForceImmediateUpdate(const QString& widgetID) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ForceImmediateUpdate(); } } void QmitkCustomMultiWidget::ForceImmediateUpdateAll() { // #TODO: Update only render windows that show the same image? // #TODO: Update only type specific render windows (2D / 3D)? for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ForceImmediateUpdate(); } } mitk::MouseModeSwitcher* QmitkCustomMultiWidget::GetMouseModeSwitcher() { return m_MouseModeSwitcher; } const mitk::Point3D QmitkCustomMultiWidget::GetCrossPosition(const QString& widgetID) const { /* 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 != NULL) && (plane2 != NULL) && (plane1->IntersectionLine(plane2, line))) { mitk::Point3D point; if ((plane3 != NULL) && (plane3->IntersectionPoint(line, point))) { return point; } } // TODO BUG POSITIONTRACKER; mitk::Point3D p; return p; // return m_LastLeftClickPositionSupplier->GetCurrentPoint(); */ return mitk::Point3D(); } ////////////////////////////////////////////////////////////////////////// // PUBLIC SLOTS ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::ShowLevelWindowWidget(const QString& widgetID, bool show) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowLevelWindowWidget(show); return; } MITK_ERROR << "Level window widget can not be shown for an unknown widget."; } void QmitkCustomMultiWidget::ShowAllLevelWindowWidgets(bool show) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ShowLevelWindowWidget(show); } } void QmitkCustomMultiWidget::SetBackgroundColorGradient(const mitk::Color& upper, const mitk::Color& lower, const QString& widgetID) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetBackgroundColorGradient(upper, lower); return; } MITK_ERROR << "Background color gradient can not be set for an unknown widget."; } void QmitkCustomMultiWidget::SetAllBackgroundColorGradients(const mitk::Color& upper, const mitk::Color& lower) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->SetBackgroundColorGradient(upper, lower); } } void QmitkCustomMultiWidget::FillAllBackgroundColorGradientsWithBlack() { float black[3] = { 0.0f, 0.0f, 0.0f }; SetAllBackgroundColorGradients(black, black); } void QmitkCustomMultiWidget::ShowBackgroundColorGradient(const QString& widgetID, bool show) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowBackgroundColorGradient(show); return; } MITK_ERROR << "Background color gradient can not be shown for an unknown widget."; } void QmitkCustomMultiWidget::ShowAllBackgroundColorGradients(bool show) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ShowBackgroundColorGradient(show); } } std::pair QmitkCustomMultiWidget::GetBackgroundColorGradient(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetRendererBackgroundColorGradient(); } 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 QmitkCustomMultiWidget::GetBackgroundColorGradientFlag(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetBackgroundColorGradientFlag(); } MITK_ERROR << "Background color gradient flag can not be retrieved for an unknown widget. Returning 'false'."; return false; } void QmitkCustomMultiWidget::SetDepartmentLogoPath(const char* path) { /* old m_LogoRendering->SetLogoImagePath(path); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow()); m_LogoRendering->Update(renderer); RequestUpdate(); */ /* new QImage* qimage = new QImage(path); vtkSmartPointer qImageToVtk; qImageToVtk = vtkSmartPointer::New(); qImageToVtk->SetQImage(qimage); qImageToVtk->Update(); m_LogoRendering->SetLogoImage(qImageToVtk->GetOutput()); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow()); m_LogoRendering->Update(renderer); RequestUpdate(); */ } void QmitkCustomMultiWidget::ShowDepartmentLogo(const QString& widgetID, bool show) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { GetRenderWindowWidget(widgetID)->ShowDepartmentLogo(show); RequestUpdate(widgetID); } MITK_ERROR << "Department logo can not be shown for an unknown widget."; return; } void QmitkCustomMultiWidget::ShowAllDepartmentLogos(bool show) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ShowDepartmentLogo(show); } } void QmitkCustomMultiWidget::SetDecorationColor(const QString& widgetID, const mitk::Color& color) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetDecorationColor(color); } MITK_ERROR << "Decoration color can not be set for an unknown widget."; } mitk::Color QmitkCustomMultiWidget::GetDecorationColor(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { 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 QmitkCustomMultiWidget::ShowColoredRectangle(const QString& widgetID, bool show) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowColoredRectangle(show); } MITK_ERROR << "Colored rectangle can not be set for an unknown widget."; } void QmitkCustomMultiWidget::ShowAllColoredRectangles(bool show) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ShowColoredRectangle(show); } } bool QmitkCustomMultiWidget::IsColoredRectangleVisible(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->IsColoredRectangleVisible(); } MITK_ERROR << "Colored rectangle visibility can not be retrieved for an unknown widget. Returning 'false'."; return false; } void QmitkCustomMultiWidget::SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); } MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; } std::string QmitkCustomMultiWidget::GetCornerAnnotationText(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->GetCornerAnnotationText(); } MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; return ""; } void QmitkCustomMultiWidget::ShowCornerAnnotation(const QString& widgetID, bool show) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ShowCornerAnnotation(show); } MITK_ERROR << "Corner annotation can not be set for an unknown widget."; } void QmitkCustomMultiWidget::ShowAllCornerAnnotations(bool show) { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->ShowCornerAnnotation(show); } } bool QmitkCustomMultiWidget::IsCornerAnnotationVisible(const QString& widgetID) const { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->IsCornerAnnotationVisible(); } MITK_ERROR << "Corner annotation visibility can not be retrieved for an unknown widget. Returning 'false'."; return false; } void QmitkCustomMultiWidget::HandleCrosshairPositionEvent() { /* if (!m_PendingCrosshairPositionEvent) { m_PendingCrosshairPositionEvent = true; QTimer::singleShot(0, this, SLOT(HandleCrosshairPositionEventDelayed())); } */ } void QmitkCustomMultiWidget::HandleCrosshairPositionEventDelayed() { /* m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->m_DataStorage->GetSubset(isImageData).GetPointer(); mitk::DataNode::Pointer node; mitk::DataNode::Pointer topSourceNode; mitk::Image::Pointer image; bool isBinary = false; node = this->GetTopLayerNode(nodes); int component = 0; if (node.IsNotNull()) { node->GetBoolProperty("binary", isBinary); if (isBinary) { mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = m_DataStorage->GetSources(node, NULL, true); if (!sourcenodes->empty()) { topSourceNode = this->GetTopLayerNode(sourcenodes); } 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); } } mitk::Point3D crosshairPos = this->GetCrossPosition(); std::string statusText; std::stringstream stream; itk::Index<3> p; mitk::BaseRenderer *baseRenderer = GetRenderWindow()->GetSliceNavigationController()->GetRenderer(); 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"; stream << "; Index: <" << p[0] << ", " << p[1] << ", " << p[2] << "> "; mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(baseRenderer->GetTimeStep()), p, pixelValue, component); if (fabs(pixelValue) > 1000000 || fabs(pixelValue) < 0.01) { stream << "; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: " << std::scientific << pixelValue << " "; } else { stream << "; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: " << pixelValue << " "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); */ } void QmitkCustomMultiWidget::Fit() { // #TODO: what is this function's purpose? /* vtkSmartPointer vtkrenderer; size_t numberOfRenderWindowWidgets = m_RenderWindowWidgets.size(); for (size_t i = 0; i < numberOfRenderWindowWidgets; ++i) { vtkRenderer* renderer = GetRenderWindow(widgetID)->GetRenderer()->GetVtkRenderer(); mitk::BaseRenderer* baseRenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow(i)->GetRenderWindow()); vtkrenderer = baseRenderer->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } baseRenderer->GetCameraController()->Fit(); } int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkObject::SetGlobalWarningDisplay(w); */ } void QmitkCustomMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) { // #TODO: what is this function's purpose? /* 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 QmitkCustomMultiWidget::MoveCrossToPosition(const QString& widgetID, const mitk::Point3D& newPosition) { QmitkRenderWindowWidget* renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { GetRenderWindowWidget(widgetID)->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindowWidget(widgetID)->RequestUpdate(); } MITK_ERROR << "Geometry plane can not be shown for an unknown widget."; } void QmitkCustomMultiWidget::ResetCrosshair() { // #TODO: new concept: we do not want to initialize all views; // we do not want to rely on the geometry planes /* if (m_DataStorage.IsNotNull()) { m_RenderingManager->InitializeViewsByBoundingObjects(m_DataStorage); // m_RenderingManager->InitializeViews( m_DataStorage->ComputeVisibleBoundingGeometry3D() ); // reset interactor to normal slicing SetWidgetPlaneMode(PLANE_MODE_SLICING); } */ } ////////////////////////////////////////////////////////////////////////// // MOUSE EVENTS ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkCustomMultiWidget::mousePressEvent(QMouseEvent* e) { } void QmitkCustomMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the overlays as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::InitializeGUI() { m_CustomMultiWidgetLayout = new QGridLayout(this); m_CustomMultiWidgetLayout->setContentsMargins(0, 0, 0, 0); setLayout(m_CustomMultiWidgetLayout); } void QmitkCustomMultiWidget::InitializeWidget() { // #TODO: some things have to be handled globally (hold for all render window (widgets) // analyse those things and design a controlling mechanism // necessary here? mouse mode is valid for all render windows (and also used in editor) m_MouseModeSwitcher = mitk::MouseModeSwitcher::New(); m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::MITK); // setup the department logo rendering /* m_LogoRendering = mitk::LogoOverlay::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.15); m_LogoRendering->SetCornerPosition(1); m_LogoRendering->SetLogoImagePath("DefaultLogo"); renderer4->GetOverlayManager()->AddOverlay(m_LogoRendering.GetPointer(), renderer4); */ } -void QmitkCustomMultiWidget::AddRenderWindowWidget() +void QmitkCustomMultiWidget::AddRenderWindowWidget(int column, int row, const std::string& cornerAnnotation/* = ""*/) { // #TODO: add QSplitter? // #TODO: include technique, to set the image to level-slide on using the render window manager // create the render window widget and connect signals / slots mitk::UIDGenerator generator; std::string renderWindowUID = generator.GetUID(); QString UID = m_MultiWidgetName + "_" + QString::fromStdString(renderWindowUID); QmitkRenderWindowWidget* renderWindowWidget = new QmitkRenderWindowWidget(this, UID, m_DataStorage); + renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); // create connections connect(renderWindowWidget, SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); connect(renderWindowWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); // store the newly created render window widget with the UID m_RenderWindowWidgets.insert(std::pair(UID, renderWindowWidget)); // #TODO: define the grid cell to add the new render window widget // add the newly created render window widget to this multi widget - m_CustomMultiWidgetLayout->addWidget(renderWindowWidget); + m_CustomMultiWidgetLayout->addWidget(renderWindowWidget, row, column); } mitk::DataNode::Pointer QmitkCustomMultiWidget::GetTopLayerNode(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { // #TODO: see T24173 return nodes->front(); } diff --git a/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp b/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp index 3a909c39cd..b3b91efd71 100644 --- a/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp +++ b/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp @@ -1,115 +1,112 @@ /*=================================================================== 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 "QmitkMouseModeSwitcher.h" #include -QmitkMouseModeSwitcher::QmitkMouseModeSwitcher(QWidget *parent) - : QToolBar(parent), - m_ActionGroup(new QActionGroup(this)), - m_MouseModeSwitcher(nullptr), - m_ObserverTag(0), - m_InObservationReaction(false) +QmitkMouseModeSwitcher::QmitkMouseModeSwitcher(QWidget* parent/* = nullptr*/) + : QToolBar(parent) + , m_ActionGroup(new QActionGroup(this)) + , m_MouseModeSwitcher(nullptr) + , m_ObserverTag(0) + , m_ActionButtonBlocked(false) { QToolBar::setOrientation(Qt::Vertical); QToolBar::setIconSize(QSize(17, 17)); - m_ActionGroup->setExclusive(true); // only one selectable + m_ActionGroup->setExclusive(true); // only one selectable action addButton(mitk::MouseModeSwitcher::MousePointer, tr("Pointer"), QIcon(":/Qmitk/mm_pointer.png"), true); // toggle ON addButton(mitk::MouseModeSwitcher::Scroll, tr("Scroll"), QIcon(":/Qmitk/mm_scroll.png")); addButton(mitk::MouseModeSwitcher::LevelWindow, tr("Level/Window"), QIcon(":/Qmitk/mm_contrast.png")); addButton(mitk::MouseModeSwitcher::Zoom, tr("Zoom"), QIcon(":/Qmitk/mm_zoom.png")); addButton(mitk::MouseModeSwitcher::Pan, tr("Pan"), QIcon(":/Qmitk/mm_pan.png")); } void QmitkMouseModeSwitcher::addButton(MouseMode id, const QString &toolName, const QIcon &icon, bool on) { - QAction *action = new QAction(icon, toolName, this); + QAction* action = new QAction(icon, toolName, this); action->setCheckable(true); action->setActionGroup(m_ActionGroup); action->setChecked(on); action->setData(id); - connect(action, SIGNAL(triggered()), this, SLOT(modeSelectedByUser())); + connect(action, SIGNAL(triggered()), this, SLOT(OnMouseModeChangedViaButton())); QToolBar::addAction(action); } QmitkMouseModeSwitcher::~QmitkMouseModeSwitcher() { - if (m_MouseModeSwitcher) + if (nullptr != m_MouseModeSwitcher) { m_MouseModeSwitcher->RemoveObserver(m_ObserverTag); } } void QmitkMouseModeSwitcher::setMouseModeSwitcher(mitk::MouseModeSwitcher *mms) { // goodbye / welcome ceremonies - if (m_MouseModeSwitcher) + if (nullptr != m_MouseModeSwitcher) { m_MouseModeSwitcher->RemoveObserver(m_ObserverTag); } m_MouseModeSwitcher = mms; if (m_MouseModeSwitcher) { - itk::ReceptorMemberCommand::Pointer command = - itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction(this, &QmitkMouseModeSwitcher::OnMouseModeChanged); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkMouseModeSwitcher::OnMouseModeChangedViaCommand); m_ObserverTag = m_MouseModeSwitcher->AddObserver(mitk::MouseModeSwitcher::MouseModeChangedEvent(), command); } } -void QmitkMouseModeSwitcher::modeSelectedByUser() +void QmitkMouseModeSwitcher::OnMouseModeChangedViaButton() { - if (m_InObservationReaction) - return; // this was NOT actually by the user but by ourselves - - QAction *action = dynamic_cast(sender()); + if (m_ActionButtonBlocked) + { + return; // blocked, since we change the checked state of the buttons in the callback function + } + QAction* action = dynamic_cast(sender()); if (action) { MouseMode id = static_cast(action->data().toInt()); // qDebug() << "Mouse mode '" << qPrintable(action->text()) << "' selected, trigger mode id " << id; if (m_MouseModeSwitcher) { m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::PACS); m_MouseModeSwitcher->SelectMouseMode(id); } emit MouseModeSelected(id); } } -void QmitkMouseModeSwitcher::OnMouseModeChanged(const itk::EventObject &) +void QmitkMouseModeSwitcher::OnMouseModeChangedViaCommand(const itk::EventObject &) { - m_InObservationReaction = true; + m_ActionButtonBlocked = true; - // push button graphically assert(m_MouseModeSwitcher); - MouseMode activeMode = m_MouseModeSwitcher->GetCurrentMouseMode(); - - foreach (QAction *action, m_ActionGroup->actions()) + foreach(QAction* action, m_ActionGroup->actions()) { if (action->data().toInt() == activeMode) { action->setChecked(true); } } - m_InObservationReaction = false; + m_ActionButtonBlocked = false; }