diff --git a/Modules/Core/include/mitkCustomDisplayActionEventHandler.h b/Modules/Core/include/mitkCustomDisplayActionEventHandler.h index da09c67a89..68eb37b6c9 100644 --- a/Modules/Core/include/mitkCustomDisplayActionEventHandler.h +++ b/Modules/Core/include/mitkCustomDisplayActionEventHandler.h @@ -1,92 +1,96 @@ /*=================================================================== 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 MITKCUSTOMDISPLAYACTIONEVENTHANDLER_H #define MITKCUSTOMDISPLAYACTIONEVENTHANDLER_H #include // mitk core #include "mitkDisplayActionEventBroadcast.h" #include "mitkDisplayInteractor.h" #include "mitkDisplayActionEvents.h" #include "mitkStdFunctionCommand.h" #include "mitkWeakPointer.h" // c++ #include namespace mitk { class MITKCORE_EXPORT CustomDisplayActionEventHandler { public: + + using OberserverTagType = unsigned long; + /** * @brief Sets the display action event broadcast class that should be observed. * This class receives events from the given broadcast class and triggers the "corresponding functions" to perform the custom actions. * "Corresponding functions" are std::functions inside commands that observe the specific display action event. * * @post If the same broadcast class was already set, nothing changed - * @post If a different broadcast class was already set, the observing commands are removed as observer - * #TODO: Do we want to have the current observing commands observe the new broadcast class? + * @post If a different broadcast class was already set, the observing commands are removed as observer. + * Attention: All registered commands are removed from the list of observer. * * @par observableBroadcast The 'DisplayActionEventBroadcast'-class that should be observed. */ void SetObservableBroadcast(mitk::DisplayActionEventBroadcast* observableBroadcast); /** - * @brief Creates a 'StdFunctionCommand' and uses the given std::functions to customize the command. + * @brief Uses the given std::functions to customize a command: * The display action event is used to define on which event the command should react. * The display action event broadcast class member is then observed by the newly created command. * A tag for the command is returned and stored in a member vector. * * @pre The class' observable (the display action event broadcast) has to be set to connect display events. * @throw mitk::Exception, if the class' observable is null. * * @par displayActionEvent The 'DisplayActionEvent' on which the command should react. * @par actionFunction A custom std::Function that will be executed if the command receives the correct event. * @par filterFunction A custom std::Function that will be checked before the execution of the action function. * If the filter function is not specified, a default filter always returning 'true' will be used. * - * @return An unsigned long tag to identify, receive or remove the newly created 'StdFunctionCommand'. + * @return A tag to identify, receive or remove the newly created 'StdFunctionCommand'. */ - unsigned long ConnectDisplayActionEvent(const mitk::DisplayActionEvent& displayActionEvent, + OberserverTagType ConnectDisplayActionEvent(const mitk::DisplayActionEvent& displayActionEvent, const mitk::StdFunctionCommand::ActionFunction& actionFunction, const mitk::StdFunctionCommand::FilterFunction& filterFunction = [](const itk::EventObject& eventObject) { return true; }); /** * @brief Uses the given observer tag to remove the corresponding custom StdFunctionCommand as an observer of the observed * display action event broadcast class. * If the given tag is not contained in the member vector of observer tags, nothing happens. * * @pre The class' observable (the display action event broadcast) has to be set to connect display events. * @throw mitk::Exception, if the class' observable is null. * - * @par observerTag The unsigned long tag to identify the 'StdFunctionCommand' observer. + * @par observerTag The tag to identify the 'StdFunctionCommand' observer. */ - void DisconnectObserver(unsigned long observerTag); + void DisconnectObserver(OberserverTagType observerTag); - const std::vector& GetAllObserverTags() { return m_ObserverTags; }; + const std::vector& GetAllObserverTags() { return m_ObserverTags; }; private: + mitk::WeakPointer m_ObservableBroadcast; - std::vector m_ObserverTags; + std::vector m_ObserverTags; }; } // end namespace mitk #endif // MITKCUSTOMDISPLAYACTIONEVENTHANDLER_H diff --git a/Modules/Core/include/mitkStdDisplayActionEventHandler.h b/Modules/Core/include/mitkStdDisplayActionEventHandler.h index 46542edbcb..8f37438cf0 100644 --- a/Modules/Core/include/mitkStdDisplayActionEventHandler.h +++ b/Modules/Core/include/mitkStdDisplayActionEventHandler.h @@ -1,58 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKSTDDISPLAYACTIONEVENTHANDLER_H #define MITKSTDDISPLAYACTIONEVENTHANDLER_H #include // mitk core #include "mitkDisplayActionEventBroadcast.h" namespace mitk { class MITKCORE_EXPORT StdDisplayActionEventHandler { public: + + using OberserverTagType = unsigned long; + /** * @brief Sets the display action event broadcast class that should be observed. * This class receives events from the given broadcast class and triggers the "corresponding functions" to perform the custom actions. * "Corresponding functions" are std::functions inside commands that observe the specific display action event. * * @post If the same broadcast class was already set, nothing changed - * @post If a different broadcast class was already set, the observing commands are removed as observer - * #TODO: Do we want to have the current observing commands observe the new broadcast class? + * @post If a different broadcast class was already set, the observing commands are removed as observer. + * Attention: All registered commands are removed from the list of observer. * * @par observableBroadcast The 'DisplayActionEventBroadcast'-class that should be observed. */ void SetObservableBroadcast(mitk::DisplayActionEventBroadcast* observableBroadcast); + /** + * @brief Initializes common standard display actions by calling the private 'ConnectDisplay...'-functions. + * + * @pre The class' observable (the display action event broadcast) has to be set to connect display events. + * @throw mitk::Exception, if the class' observable is null. + */ void InitStdActions(); private: + /** + * @brief Registers a command as observer of the observable broadcast class. + * This command reacts on the 'DisplayMoveEvent' and performs a move of the camera controller + * by a vector that was previously determined by the mouse interaction event. + */ void ConnectDisplayMoveEvent(); + /** + * @brief Registers a command as observer of the observable broadcast class. + * This command reacts on the 'DisplaySetCrosshairEvent' and performs a slice selection of the slice navigation controller. + * The new position was previously determined by the mouse interaction event. + */ void ConnectDisplaySetCrosshairEvent(); + /** + * @brief Registers a command as observer of the observable broadcast class. + * This command reacts on the 'DisplayZoomEvent' and performs a zoom of the camera controller + * by a zoom factor that was previously determined by the mouse interaction event. + */ void ConnectDisplayZoomEvent(); + /** + * @brief Registers a command as observer of the observable broadcast class. + * This command reacts on the 'DisplayScrollEvent' and performs a slice selection of the slice navigation controller. + * The new position was previously determined by the mouse interaction event. + */ void ConnectDisplayScrollEvent(); mitk::WeakPointer m_ObservableBroadcast; - std::vector m_ObserverTags; + std::vector m_ObserverTags; }; } // end namespace mitk #endif // MITKSTDDISPLAYACTIONEVENTHANDLER_H diff --git a/Modules/Core/src/Interactions/mitkCustomDisplayActionEventHandler.cpp b/Modules/Core/src/Interactions/mitkCustomDisplayActionEventHandler.cpp index 6d03f83bcc..5e3607a41c 100644 --- a/Modules/Core/src/Interactions/mitkCustomDisplayActionEventHandler.cpp +++ b/Modules/Core/src/Interactions/mitkCustomDisplayActionEventHandler.cpp @@ -1,77 +1,76 @@ /*=================================================================== 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 "mitkCustomDisplayActionEventHandler.h" // c++ #include void mitk::CustomDisplayActionEventHandler::SetObservableBroadcast(mitk::DisplayActionEventBroadcast* observableBroadcast) { if (m_ObservableBroadcast == observableBroadcast) { // no need to update the broadcast class return; } if (m_ObservableBroadcast.IsNotNull()) { // remove current observer for (const auto& tag : m_ObserverTags) { m_ObservableBroadcast->RemoveObserver(tag); } - // #TODO: decide if we want to move the observer to the new observable broadcast class m_ObserverTags.clear(); } // set new broadcast class (possibly nullptr) m_ObservableBroadcast = observableBroadcast; } unsigned long mitk::CustomDisplayActionEventHandler::ConnectDisplayActionEvent(const mitk::DisplayActionEvent& displayActionEvent, const mitk::StdFunctionCommand::ActionFunction& actionFunction, const mitk::StdFunctionCommand::FilterFunction& filterFunction) { // #TODO: change function call for new mitk::WeakPointer if (m_ObservableBroadcast.IsNull()) { mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before connecting events."; } auto command = mitk::StdFunctionCommand::New(); command->SetCommandAction(actionFunction); command->SetCommandFilter(filterFunction); unsigned long tag = m_ObservableBroadcast->AddObserver(displayActionEvent, command); m_ObserverTags.push_back(tag); return tag; } void mitk::CustomDisplayActionEventHandler::DisconnectObserver(unsigned long observerTag) { // #TODO: change function call for new mitk::WeakPointer if (m_ObservableBroadcast.IsNull()) { mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before disconnecting observer."; } std::vector::iterator observerTagPosition = std::find(m_ObserverTags.begin(), m_ObserverTags.end(), observerTag); if (observerTagPosition != m_ObserverTags.end()) { m_ObservableBroadcast->RemoveObserver(observerTag); m_ObserverTags.erase(observerTagPosition); } } diff --git a/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp b/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp index d4934092a3..0da21a7eb1 100644 --- a/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp +++ b/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp @@ -1,155 +1,154 @@ /*=================================================================== 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 "mitkStdDisplayActionEventHandler.h" // mitk core #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkDisplayActionEvents.h" #include "mitkStdFunctionCommand.h" // itk #include void mitk::StdDisplayActionEventHandler::SetObservableBroadcast(mitk::DisplayActionEventBroadcast* observableBroadcast) { if (m_ObservableBroadcast == observableBroadcast) { // no need to update the broadcast class return; } if (m_ObservableBroadcast.IsNotNull()) { // remove current observer for (const auto& tag : m_ObserverTags) { m_ObservableBroadcast->RemoveObserver(tag); } - // #TODO: decide if we want to move the observer to the new observable broadcast class m_ObserverTags.clear(); } // set new (possibly nullptr) broadcast class m_ObservableBroadcast = observableBroadcast; } void mitk::StdDisplayActionEventHandler::InitStdActions() { // #TODO: change function call for new mitk::WeakPointer if (m_ObservableBroadcast.IsNull()) { mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before initializing actions."; } ConnectDisplayMoveEvent(); ConnectDisplaySetCrosshairEvent(); ConnectDisplayZoomEvent(); ConnectDisplayScrollEvent(); } void mitk::StdDisplayActionEventHandler::ConnectDisplayMoveEvent() { auto command = StdFunctionCommand::New(); auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) { const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetInteractionEvent()->GetSender(); // concrete action sendingRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); } }; command->SetCommandAction(actionFunction); unsigned long tag = m_ObservableBroadcast->AddObserver(DisplayMoveEvent(nullptr, Vector2D()), command); m_ObserverTags.push_back(tag); } void mitk::StdDisplayActionEventHandler::ConnectDisplaySetCrosshairEvent() { auto command = StdFunctionCommand::New(); auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetInteractionEvent()->GetSender(); // concrete action auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : allRenderWindows) { if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard2D && renWin != sendingRenderer->GetRenderWindow()) { BaseRenderer::GetInstance(renWin)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); } } } }; command->SetCommandAction(actionFunction); unsigned long tag = m_ObservableBroadcast->AddObserver(DisplaySetCrosshairEvent(nullptr, Point3D()), command); m_ObserverTags.push_back(tag); } void mitk::StdDisplayActionEventHandler::ConnectDisplayZoomEvent() { auto command = StdFunctionCommand::New(); auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) { const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetInteractionEvent()->GetSender(); // concrete action if (1.0 != displayActionEvent->GetZoomFactor()) { sendingRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); } } }; command->SetCommandAction(actionFunction); unsigned long tag = m_ObservableBroadcast->AddObserver(DisplayZoomEvent(nullptr, 0.0, Point2D()), command); m_ObserverTags.push_back(tag); } void mitk::StdDisplayActionEventHandler::ConnectDisplayScrollEvent() { auto command = StdFunctionCommand::New(); auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) { const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetInteractionEvent()->GetSender(); // concrete action sendingRenderer->GetSliceNavigationController()->GetSlice()->SetPos(displayActionEvent->GetPosition()); } }; command->SetCommandAction(actionFunction); unsigned long tag = m_ObservableBroadcast->AddObserver(DisplayScrollEvent(nullptr, 0), command); m_ObserverTags.push_back(tag); } \ No newline at end of file