diff --git a/Modules/Core/include/mitkDisplayActionEventFunctions.h b/Modules/Core/include/mitkDisplayActionEventFunctions.h index 341674995e..00ce9331a8 100644 --- a/Modules/Core/include/mitkDisplayActionEventFunctions.h +++ b/Modules/Core/include/mitkDisplayActionEventFunctions.h @@ -1,55 +1,81 @@ /*=================================================================== 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 MITKDISPLAYACTIONEVENTFUNCTIONS_H #define MITKDISPLAYACTIONEVENTFUNCTIONS_H +#include + #include "mitkStdFunctionCommand.h" namespace mitk { namespace DisplayActionEventFunctions { /** * @brief Returns a command that reacts on the 'DisplayMoveEvent'. * The command performs a move of the camera controller of the sending renderer by a vector * that was previously determined by the mouse interaction event. */ - StdFunctionCommand::ActionFunction MoveSenderCameraAction(); + MITKCORE_EXPORT StdFunctionCommand::ActionFunction MoveSenderCameraAction(); /** * @brief Returns a command that reacts on the 'DisplaySetCrosshairEvent'. * The command performs a slice selection of the slice navigation controller and will set * the cross hair for all render windows. * The new position was previously determined by the mouse interaction event. */ - StdFunctionCommand::ActionFunction SetCrosshairAction(); + MITKCORE_EXPORT StdFunctionCommand::ActionFunction SetCrosshairAction(); /** * @brief Returns a command that reacts on the 'DisplayZoomEvent'. * The command performs a zoom of the camera controller of the sending renderer by a zoom factor * that was previously determined by the mouse interaction event. */ - StdFunctionCommand::ActionFunction ZoomSenderCameraAction(); + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ZoomSenderCameraAction(); /** * @brief Returns a command that reacts on the 'DisplayScrollEvent'. * The command performs a slice scrolling of the slice navigation controller of the sending renderer. * The new position was previously determined by the mouse interaction event. */ - StdFunctionCommand::ActionFunction ScrollSliceStepperAction(); + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ScrollSliceStepperAction(); + /** + * @brief + * + * + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction MoveCameraSynchronizedAction(); + /** + * @brief + * + * + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction SetCrosshairSynchronizedAction(); + /** + * @brief + * + * + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ZoomCameraSynchronizedAction(); + /** + * @brief + * + * + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ScrollSliceStepperSynchronizedAction(); } // end namespace DisplayActionEventFunctions } // end namespace mitk #endif // MITKDISPLAYACTIONEVENTFUNCTIONS_H diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp index 6e8df75f1f..fe6eed8143 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp @@ -1,139 +1,285 @@ /*=================================================================== 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 "mitkDisplayActionEventFunctions.h" // mitk core #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkDisplayActionEvents.h" +////////////////////////////////////////////////////////////////////////// +// STANDARD FUNCTIONS +////////////////////////////////////////////////////////////////////////// mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveSenderCameraAction() { mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) { const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action sendingRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); - for (auto renWin : allRenderWindows) + for (auto renderWindow : allRenderWindows) { - if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard2D && renWin != sendingRenderer->GetRenderWindow()) + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D && renderWindow != sendingRenderer->GetRenderWindow()) { - BaseRenderer::GetInstance(renWin)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); + BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomSenderCameraAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) { const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action if (1.0 != displayActionEvent->GetZoomFactor()) { sendingRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) { const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // concrete action mitk::SliceNavigationController* sliceNavigationController = sendingRenderer->GetSliceNavigationController(); if (nullptr == sliceNavigationController) { return; } if (sliceNavigationController->GetSliceLocked()) { return; } mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); if (nullptr == sliceStepper) { return; } // if only a single slice image was loaded, scrolling will affect the time steps if (sliceStepper->GetSteps() <= 1) { sliceStepper = sliceNavigationController->GetTime(); } sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); } }; return actionFunction; } + +////////////////////////////////////////////////////////////////////////// +// SYNCHRONIZED FUNCTIONS +////////////////////////////////////////////////////////////////////////// +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction() +{ + mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + // concrete action + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); + currentRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); + currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); + } + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + // concrete action + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); + } + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + // concrete action + if (1.0 != displayActionEvent->GetZoomFactor()) + { + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); + currentRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); + currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); + } + } + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + // concrete action + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + mitk::SliceNavigationController* sliceNavigationController = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); + if (nullptr == sliceNavigationController) + { + return; + } + if (sliceNavigationController->GetSliceLocked()) + { + return; + } + mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); + if (nullptr == sliceStepper) + { + return; + } + + // if only a single slice image was loaded, scrolling will affect the time steps + if (sliceStepper->GetSteps() <= 1) + { + sliceStepper = sliceNavigationController->GetTime(); + } + + sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); + } + } + } + }; + + return actionFunction; +} diff --git a/Modules/QtWidgets/include/QmitkCustomMultiWidget.h b/Modules/QtWidgets/include/QmitkCustomMultiWidget.h index a48f368175..0e6a54dec0 100644 --- a/Modules/QtWidgets/include/QmitkCustomMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkCustomMultiWidget.h @@ -1,173 +1,175 @@ /*=================================================================== 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 #include -#include +#include // qt #include class QHBoxLayout; class QVBoxLayout; class QGridLayout; class QSpacerItem; class QmitkLevelWindowWidget; class QmitkRenderWindow; 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 InitializeRenderWindowWidgets(); void ResetLayout(int row, int column); + void Synchronize(bool synchronized); using RenderWindowWidgetMap = std::map>; using RenderWindowHash = QHash; RenderWindowWidgetMap GetRenderWindowWidgets() const; std::shared_ptr GetRenderWindowWidget(const QString& widgetID) const; QString CreateRenderWindowWidget(const std::string& cornerAnnotation = ""); void AddToMultiWidgetLayout(int row, int column, const QString& widgetID); void RemoveRenderWindowWidget(const QString& widgetID); QmitkRenderWindow* GetRenderWindow(const QString& widgetID) const; std::shared_ptr GetActiveRenderWindowWidget() const; std::shared_ptr GetFirstRenderWindowWidget() const; std::shared_ptr 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 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 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 InitializeDisplayActionEventHandling(); void FillLayout(int row, int column); // #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::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; - std::unique_ptr m_StdDisplayActionEventHandler; + std::unique_ptr m_DisplayActionEventHandler; + bool m_Synchronized; mitk::DataStorage::Pointer m_DataStorage; bool m_PendingCrosshairPositionEvent; bool m_CrosshairNavigationEnabled; }; #endif // QMITKCUSTOMMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h b/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h index 53d9e3f5ea..5fdf62d152 100644 --- a/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h +++ b/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h @@ -1,62 +1,67 @@ /*=================================================================== 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 #include // mitk qtwidgets #include "QmitkCustomMultiWidget.h" #include "QmitkMultiWidgetLayoutSelectionWidget.h" /** * @brief * * */ class MITKQTWIDGETS_EXPORT QmitkMultiWidgetConfigurationToolBar : public QToolBar { Q_OBJECT public: QmitkMultiWidgetConfigurationToolBar(QmitkCustomMultiWidget* customMultiWidget); ~QmitkMultiWidgetConfigurationToolBar() override; signals: void LayoutSet(int row, int column); + void Synchronized(bool synchronized); protected slots: void OnSetLayout(); + void OnSynchronize(); private: void InitActionGroup();; void AddButtons(); QActionGroup* m_ActionGroup; QmitkCustomMultiWidget* m_CustomMultiWidget; + QAction* m_SynchronizeAction; + bool m_Synchronized; + QmitkMultiWidgetLayoutSelectionWidget* m_LayoutSelectionPopup; }; #endif // QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H diff --git a/Modules/QtWidgets/resource/Qmitk.qrc b/Modules/QtWidgets/resource/Qmitk.qrc index 2914780187..69e5b5704d 100644 --- a/Modules/QtWidgets/resource/Qmitk.qrc +++ b/Modules/QtWidgets/resource/Qmitk.qrc @@ -1,16 +1,18 @@ Binaerbilder_48.png Images_48.png PointSet_48.png Segmentation_48.png Surface_48.png mm_pointer.png mm_scroll.png mm_zoom.png mm_contrast.png mm_pan.png LabelSetImage_48.png cmwLayout.png + cmwSynchronized.png + cmwDesynchronized.png diff --git a/Modules/QtWidgets/resource/cmwDesynchronized.png b/Modules/QtWidgets/resource/cmwDesynchronized.png new file mode 100644 index 0000000000..81f087582c Binary files /dev/null and b/Modules/QtWidgets/resource/cmwDesynchronized.png differ diff --git a/Modules/QtWidgets/resource/cmwSynchronized.png b/Modules/QtWidgets/resource/cmwSynchronized.png new file mode 100644 index 0000000000..df4dd212ee Binary files /dev/null and b/Modules/QtWidgets/resource/cmwSynchronized.png differ diff --git a/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp b/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp index 3eead7fbff..434ae1ba5a 100644 --- a/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkCustomMultiWidget.cpp @@ -1,531 +1,576 @@ /*=================================================================== 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 // mitk core +#include +#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) , m_DisplayActionEventBroadcast(nullptr) - , m_StdDisplayActionEventHandler(nullptr) + , m_DisplayActionEventHandler(nullptr) , m_DataStorage(nullptr) { // create widget manually // create and set layout InitializeGUI(); InitializeWidget(); InitializeDisplayActionEventHandling(); resize(QSize(364, 477).expandedTo(minimumSizeHint())); } QmitkCustomMultiWidget::~QmitkCustomMultiWidget() { // nothing here } void QmitkCustomMultiWidget::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 QmitkCustomMultiWidget::InitializeRenderWindowWidgets() { // create render window (widgets) initially QString UID = CreateRenderWindowWidget("2015-01-14 - CT"); AddToMultiWidgetLayout(0, 0, UID); /* AddRenderWindowWidget(0, 1, "2015-08-19 - CT"); AddRenderWindowWidget(0, 2, "2016-06-29 - CT"); AddRenderWindowWidget(1, 0, "2015-01-14 - MR"); AddRenderWindowWidget(1, 1, "2015-08-19 - MR"); AddRenderWindowWidget(1, 2, "2016-06-29 - MR"); */ } void QmitkCustomMultiWidget::ResetLayout(int row, int column) { int neededRenderWindowWidgets = (row + 1) * (column + 1); int existingRenderWindowWidgets = m_RenderWindowWidgets.size(); int difference = neededRenderWindowWidgets - existingRenderWindowWidgets; while(0 < difference) { // more render window widgets needed CreateRenderWindowWidget(); --difference; } while(0 > difference) { // less render window widgets needed RemoveRenderWindowWidget(m_RenderWindowWidgets.rbegin()->first); ++difference; } InitializeGUI(); if (0 == difference) { FillLayout(row, column); } } +void QmitkCustomMultiWidget::Synchronize(bool synchronized) +{ + m_Synchronized = synchronized; + auto allObserverTags = m_DisplayActionEventHandler->GetAllObserverTags(); + for (auto observerTag : allObserverTags) + { + m_DisplayActionEventHandler->DisconnectObserver(observerTag); + } + + if (m_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); + + // #TODO: set equal view direction for all render windows + } + 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); + } +} + QmitkCustomMultiWidget::RenderWindowWidgetMap QmitkCustomMultiWidget::GetRenderWindowWidgets() const { return m_RenderWindowWidgets; } std::shared_ptr QmitkCustomMultiWidget::GetRenderWindowWidget(const QString& widgetID) const { RenderWindowWidgetMap::const_iterator it = m_RenderWindowWidgets.find(widgetID); if (it == m_RenderWindowWidgets.end()) { return nullptr; } return it->second; } QString QmitkCustomMultiWidget::CreateRenderWindowWidget(const std::string& cornerAnnotation/* = ""*/) { // create the render window widget and connect signals / slots mitk::UIDGenerator generator; std::string renderWindowUID = generator.GetUID(); QString UID = m_MultiWidgetName + "_" + QString::fromStdString(renderWindowUID); std::shared_ptr renderWindowWidget = std::make_shared(this, UID, m_DataStorage); renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); // create connections //connect(renderWindowWidget.get(), SIGNAL(ResetView()), this, SLOT(ResetCrosshair())); //connect(renderWindowWidget.get(), SIGNAL(ChangeCrosshairRotationMode(int)), this, SLOT(SetWidgetPlaneMode(int))); // store the newly created render window widget with the UID m_RenderWindowWidgets.insert(std::make_pair(UID, renderWindowWidget)); return UID; } void QmitkCustomMultiWidget::AddToMultiWidgetLayout(int row, int column, const QString& widgetID) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { m_CustomMultiWidgetLayout->addWidget(renderWindowWidget.get(), row, column); } } void QmitkCustomMultiWidget::RemoveRenderWindowWidget(const QString& widgetID) { auto iterator = m_RenderWindowWidgets.find(widgetID); if (iterator == m_RenderWindowWidgets.end()) { return; } std::shared_ptr renderWindowWidgetToRemove = iterator->second; disconnect(renderWindowWidgetToRemove.get(), 0, 0, 0); // erase the render window from the map m_RenderWindowWidgets.erase(iterator); // remove from layout // #TODO } QmitkRenderWindow* QmitkCustomMultiWidget::GetRenderWindow(const QString& widgetID) const { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetRenderWindow(); } return nullptr; } std::shared_ptr QmitkCustomMultiWidget::GetActiveRenderWindowWidget() const { //return m_ActiveRenderWindowWidget; return m_RenderWindowWidgets.begin()->second; } std::shared_ptr QmitkCustomMultiWidget::GetFirstRenderWindowWidget() const { if (!m_RenderWindowWidgets.empty()) { return m_RenderWindowWidgets.begin()->second; } else { return nullptr; } } std::shared_ptr QmitkCustomMultiWidget::GetLastRenderWindowWidget() const { if (!m_RenderWindowWidgets.empty()) { return m_RenderWindowWidgets.rbegin()->second; } else { return nullptr; } } unsigned int QmitkCustomMultiWidget::GetNumberOfRenderWindowWidgets() const { return m_RenderWindowWidgets.size(); } void QmitkCustomMultiWidget::RequestUpdate(const QString& widgetID) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { return renderWindowWidget->RequestUpdate(); } } void QmitkCustomMultiWidget::RequestUpdateAll() { for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->RequestUpdate(); } } void QmitkCustomMultiWidget::ForceImmediateUpdate(const QString& widgetID) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->ForceImmediateUpdate(); } } void QmitkCustomMultiWidget::ForceImmediateUpdateAll() { 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) { std::shared_ptr 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::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::MoveCrossToPosition(const QString& widgetID, const mitk::Point3D& newPosition) { std::shared_ptr renderWindowWidget = GetRenderWindowWidget(widgetID); if (nullptr != renderWindowWidget) { renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); renderWindowWidget->RequestUpdate(); return; } 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 MultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidget::InitializeGUI() { delete m_CustomMultiWidgetLayout; 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); } void QmitkCustomMultiWidget::InitializeDisplayActionEventHandling() { m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigPACS.xml"); - m_StdDisplayActionEventHandler = std::make_unique(); - m_StdDisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); - m_StdDisplayActionEventHandler->InitStdActions(); + m_DisplayActionEventHandler = std::make_unique(); + m_DisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); + + Synchronize(true); } void QmitkCustomMultiWidget::FillLayout(int row, int column) { int r = 0; int c = 0; for (const auto& renderWindowWidget : m_RenderWindowWidgets) { AddToMultiWidgetLayout(r, c, renderWindowWidget.first); c += 1; if (c > column) { // first column c = 0; // next row r += 1; if (r > row) { return; } } } } mitk::DataNode::Pointer QmitkCustomMultiWidget::GetTopLayerNode(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { // #TODO: see T24173 return nodes->front(); } diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp index 2e37063104..2fb804db98 100644 --- a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp +++ b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp @@ -1,73 +1,91 @@ /*=================================================================== 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(QmitkCustomMultiWidget* customMultiWidget) : QToolBar(customMultiWidget) , m_CustomMultiWidget(customMultiWidget) , m_ActionGroup(nullptr) { QToolBar::setOrientation(Qt::Vertical); QToolBar::setIconSize(QSize(17, 17)); InitActionGroup(); } QmitkMultiWidgetConfigurationToolBar::~QmitkMultiWidgetConfigurationToolBar() { // nothing here } void QmitkMultiWidgetConfigurationToolBar::InitActionGroup() { m_ActionGroup = new QActionGroup(this); m_ActionGroup->setExclusive(true); // create popup to show a widget to modify the multi widget layout m_LayoutSelectionPopup = new QmitkMultiWidgetLayoutSelectionWidget(this); m_LayoutSelectionPopup->hide(); AddButtons(); connect(m_LayoutSelectionPopup, SIGNAL(LayoutSet(int, int)), SIGNAL(LayoutSet(int, int))); } void QmitkMultiWidgetConfigurationToolBar::AddButtons() { QAction* setLayoutAction = new QAction(QIcon(":/Qmitk/cmwLayout.png"), tr("Set multi widget layout"), this); setLayoutAction->setActionGroup(m_ActionGroup); connect(setLayoutAction, SIGNAL(triggered()), SLOT(OnSetLayout())); QToolBar::addAction(setLayoutAction); + m_SynchronizeAction = new QAction(QIcon(":/Qmitk/cmwSynchronized.png"), tr("Desynchronize render windows"), this); + m_SynchronizeAction->setActionGroup(m_ActionGroup); + connect(m_SynchronizeAction, SIGNAL(triggered()), SLOT(OnSynchronize())); + m_Synchronized = true; + + QToolBar::addAction(m_SynchronizeAction); } void QmitkMultiWidgetConfigurationToolBar::OnSetLayout() { if (nullptr != m_CustomMultiWidget) { m_LayoutSelectionPopup->setWindowFlags(Qt::Popup); m_LayoutSelectionPopup->move(this->cursor().pos()); m_LayoutSelectionPopup->show(); } } +void QmitkMultiWidgetConfigurationToolBar::OnSynchronize() { + m_Synchronized = !m_Synchronized; + if (m_Synchronized) + { + m_SynchronizeAction->setIcon(QIcon(":/Qmitk/cmwSynchronized.png")); + m_SynchronizeAction->setText(tr("Desynchronize render windows")); + } + else { + m_SynchronizeAction->setIcon(QIcon(":/Qmitk/cmwDesynchronized.png")); + m_SynchronizeAction->setText(tr("Synchronize render windows")); } -} \ No newline at end of file + + emit Synchronized(m_Synchronized); +} diff --git a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp index cb77315b5b..e64a4f2b89 100644 --- a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.cpp @@ -1,222 +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. ===================================================================*/ #include "QmitkCustomMultiWidgetEditor.h" #include #include #include #include #include // mitk core #include #include const QString QmitkCustomMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.custommultiwidget"; QmitkCustomMultiWidgetEditor::QmitkCustomMultiWidgetEditor() : m_CustomMultiWidget(nullptr) , m_MouseModeSwitcher(nullptr) , m_ConfigurationToolBar(nullptr) { // nothing here } QmitkCustomMultiWidgetEditor::~QmitkCustomMultiWidgetEditor() { // nothing here } void QmitkCustomMultiWidgetEditor::Activated() { // nothing here } void QmitkCustomMultiWidgetEditor::Deactivated() { // nothing here } void QmitkCustomMultiWidgetEditor::Visible() { // nothing here } void QmitkCustomMultiWidgetEditor::Hidden() { // nothing here } QmitkRenderWindow* QmitkCustomMultiWidgetEditor::GetActiveQmitkRenderWindow() const { if (nullptr != m_CustomMultiWidget) { return m_CustomMultiWidget->GetActiveRenderWindowWidget()->GetRenderWindow(); } return nullptr; } QHash QmitkCustomMultiWidgetEditor::GetQmitkRenderWindows() const { QHash result; if (nullptr == m_CustomMultiWidget) { return result; } // create QHash on demand QmitkCustomMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_CustomMultiWidget->GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); } return result; } QmitkRenderWindow* QmitkCustomMultiWidgetEditor::GetQmitkRenderWindow(const QString& id) const { if (nullptr == m_CustomMultiWidget) { return nullptr; } return m_CustomMultiWidget->GetRenderWindow(id); } mitk::Point3D QmitkCustomMultiWidgetEditor::GetSelectedPosition(const QString& id) const { if (nullptr == m_CustomMultiWidget) { return mitk::Point3D(); } return m_CustomMultiWidget->GetCrossPosition(id); } void QmitkCustomMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D& pos, const QString& id) { if (nullptr != m_CustomMultiWidget) { m_CustomMultiWidget->MoveCrossToPosition(id, pos); } } void QmitkCustomMultiWidgetEditor::EnableDecorations(bool enable, const QStringList& decorations) { m_MultiWidgetDecorationManager->ShowDecorations(enable, decorations); } bool QmitkCustomMultiWidgetEditor::IsDecorationEnabled(const QString& decoration) const { return m_MultiWidgetDecorationManager->IsDecorationVisible(decoration); } QStringList QmitkCustomMultiWidgetEditor::GetDecorations() const { return m_MultiWidgetDecorationManager->GetDecorations(); } void QmitkCustomMultiWidgetEditor::EnableSlicingPlanes(bool enable) { // #TODO: nothing here } bool QmitkCustomMultiWidgetEditor::IsSlicingPlanesEnabled() const { // #TODO: nothing here return false; } QmitkCustomMultiWidget* QmitkCustomMultiWidgetEditor::GetCustomMultiWidget() { return m_CustomMultiWidget; } void QmitkCustomMultiWidgetEditor::OnLayoutSet(int row, int column) { m_CustomMultiWidget->ResetLayout(row, column); } +void QmitkCustomMultiWidgetEditor::OnSynchronize(bool synchronized) +{ + m_CustomMultiWidget->Synchronize(synchronized); +} + ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkCustomMultiWidgetEditor::SetFocus() { if (nullptr != m_CustomMultiWidget) { m_CustomMultiWidget->setFocus(); } } void QmitkCustomMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { if (nullptr == m_CustomMultiWidget) { 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)); m_CustomMultiWidget = new QmitkCustomMultiWidget(parent, 0, 0, renderingMode); // create left toolbar: mouse mode toolbar to switch how the render window navigation behaves if (nullptr == m_MouseModeSwitcher) { m_MouseModeSwitcher = new QmitkMouseModeSwitcher(parent); layout->addWidget(m_MouseModeSwitcher); } m_MouseModeSwitcher->setMouseModeSwitcher(m_CustomMultiWidget->GetMouseModeSwitcher()); // add center widget: the custom multi widget layout->addWidget(m_CustomMultiWidget); m_CustomMultiWidget->SetDataStorage(GetDataStorage()); m_CustomMultiWidget->InitializeRenderWindowWidgets(); // create right toolbar: configuration toolbar to change the render window widget layout if (nullptr == m_ConfigurationToolBar) { m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(m_CustomMultiWidget); layout->addWidget(m_ConfigurationToolBar); } connect(m_ConfigurationToolBar, SIGNAL(LayoutSet(int, int)), SLOT(OnLayoutSet(int, int))); + connect(m_ConfigurationToolBar, SIGNAL(Synchronized(bool)), SLOT(OnSynchronize(bool))); m_MultiWidgetDecorationManager = std::make_unique(m_CustomMultiWidget); OnPreferencesChanged(preferences); } } void QmitkCustomMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { // update decoration preferences m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); // zooming and panning preferences bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); // level window preferences bool showLevelWindowWidget = preferences->GetBool("Show level-window widget", true); m_CustomMultiWidget->ShowAllLevelWindowWidgets(showLevelWindowWidget); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.h index 810480fba5..4036fe03a9 100644 --- a/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.h +++ b/Plugins/org.mitk.gui.qt.custommultiwidgeteditor/src/QmitkCustomMultiWidgetEditor.h @@ -1,141 +1,142 @@ /*=================================================================== 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 QMITKCUSTOMMULTIWIDGETEDITOR_H #define QMITKCUSTOMMULTIWIDGETEDITOR_H #include #include #include // custom multi widget editor #include #include "QmitkMultiWidgetDecorationManager.h" // qt widgets module #include #include #include #include class QmitkMouseModeSwitcher; class CUSTOMMULTIWIDGETEDITOR_EXPORT QmitkCustomMultiWidgetEditor final : public QmitkAbstractRenderEditor, public mitk::ILifecycleAwarePart, public mitk::ILinkedRenderWindowPart { Q_OBJECT public: berryObjectMacro(QmitkCustomMultiWidgetEditor) static const QString EDITOR_ID; QmitkCustomMultiWidgetEditor(); ~QmitkCustomMultiWidgetEditor(); /** * @brief Overridden from mitk::ILifecycleAwarePart */ virtual void Activated() override; /** * @brief Overridden from mitk::ILifecycleAwarePart */ virtual void Deactivated() override; /** * @brief Overridden from mitk::ILifecycleAwarePart */ virtual void Visible() override; /** * @brief Overridden from mitk::ILifecycleAwarePart */ virtual void Hidden() override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual QHash GetQmitkRenderWindows() const override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual bool IsDecorationEnabled(const QString& decoration) const override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart : IRenderWindowPart */ virtual QStringList GetDecorations() const override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart */ virtual void EnableSlicingPlanes(bool enable) override; /** * @brief Overridden from mitk::ILinkedRenderWindowPart */ virtual bool IsSlicingPlanesEnabled() const override; QmitkCustomMultiWidget* GetCustomMultiWidget(); private slots: void OnLayoutSet(int row, int column); + void OnSynchronize(bool synchronized); private: /** * @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 * * */ void RequestActivateMenuWidget(bool on); QmitkCustomMultiWidget* m_CustomMultiWidget; QmitkMouseModeSwitcher* m_MouseModeSwitcher; QmitkMultiWidgetConfigurationToolBar* m_ConfigurationToolBar; std::unique_ptr m_MultiWidgetDecorationManager; }; #endif // QMITKCUSTOMMULTIWIDGETEDITOR_H