diff --git a/Modules/Core/include/mitkLevelWindowManager.h b/Modules/Core/include/mitkLevelWindowManager.h index 8101380fdf..bf3bdcc8f7 100644 --- a/Modules/Core/include/mitkLevelWindowManager.h +++ b/Modules/Core/include/mitkLevelWindowManager.h @@ -1,161 +1,177 @@ /*=================================================================== 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 mitkLevelWindowManager_h -#define mitkLevelWindowManager_h +#ifndef MITKLEVELWINDOWMANAGER_H +#define MITKLEVELWINDOWMANAGER_H #include "mitkBaseProperty.h" #include "mitkDataStorage.h" #include "mitkLevelWindowProperty.h" #include #include namespace mitk { /** \brief Provides access to the LevelWindowProperty object and LevelWindow of the "current" image. - provides a LevelWindowProperty for purposes like GUI editors - this property comes from one of two possible sources - either something (e.g. the application) sets the property because of some user selection - OR the "Auto top-most" logic is used to search a DataStorage for the image with the highest "layer" property value Changes on Level/Window can be set with SetLevelWindow() and will affect either the topmost layer image, if isAutoTopMost() returns true, or an image which is set by SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty). Changes to Level/Window, when another image gets active or by SetLevelWindow(const LevelWindow& levelWindow), will be sent to all listeners by Modified(). DataStorageChanged() listens to the DataStorage for new or removed images. Depending on how m_AutoTopMost is set, the new image becomes active or not. If an image is removed from the DataStorage and m_AutoTopMost is false, there is a check to proof, if the active image is still available. If not, then m_AutoTopMost becomes true. Note that this class is not thread safe at the moment! */ class MITKCORE_EXPORT LevelWindowManager : public itk::Object { public: - mitkClassMacroItkParent(LevelWindowManager, itk::Object) itkFactorylessNewMacro(Self) itkCloneMacro(Self) + mitkClassMacroItkParent(LevelWindowManager, itk::Object) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) - void SetDataStorage(DataStorage *ds); - DataStorage *GetDataStorage(); ///< returns the datastorage + void SetDataStorage(DataStorage *ds); + DataStorage *GetDataStorage(); /** @brief (Re-)Initializes the LevelWindowManager by setting the topmost image. - * Use the removedNode parameter if a node was removed... - * @param autoTopMost true: sets the topmost layer image to be affected by changes - * @param removedNode != nullptr a node was removed from DataStorage */ + * Use the removedNode parameter if a node was removed. + * @param autoTopMost Sets the topmost layer image to be affected by changes, if true. + * @param removedNode A node was removed from the data storage if != nullptr. + */ void SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode = nullptr); + /** @brief (Re-)Initializes the LevelWindowManager by setting the selected images. + * Use the removedNode parameter if a node was removed. + * @param selectedImages Sets the selected images to be affected by changes, if true. + * @param removedNode A node was removed from the data storage if != nullptr. + */ + void SetSelectedImages(bool selectedImages, const DataNode *removedNode = nullptr); - void RecaluclateLevelWindowForSelectedComponent(const itk::EventObject &); + void RecalculateLevelWindowForSelectedComponent(const itk::EventObject &); void Update(const itk::EventObject &e); ///< gets called if a visible property changes - /** @brief Sets an specific LevelWindowProperty, all changes will affect the image belonging to this property. + /** @brief Set a specific LevelWindowProperty; all changes will affect the image belonging to this property. * @throw mitk::Exception Throws an exception if the there is no image in the data storage which belongs to this * property.*/ void SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty); /** @brief Sets new Level/Window values and informs all listeners about changes. */ void SetLevelWindow(const LevelWindow &levelWindow); /** @return Returns Level/Window values for the current image.*/ const LevelWindow &GetLevelWindow(); /** @return Returns the current mitkLevelWindowProperty object from the image that is affected by changes.*/ LevelWindowProperty::Pointer GetLevelWindowProperty(); - /** @return true if changes on slider or line-edits will affect always the topmost layer image. */ - bool isAutoTopMost(); + /** @return true if changes on slider or line-edits will affect the topmost layer image. */ + bool IsAutoTopMost(); + + /** @return true if changes on slider or line-edits will affect the currently selected images. */ + bool IsSelectedImages(); /** @brief This method is called when a node is added to the data storage. * A listener on the data storage is used to call this method automatically after a node was added. * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from * the * number of nodes. */ void DataStorageAddedNode(const DataNode *n = nullptr); /** @brief This method is called when a node is removed to the data storage. * A listener on the data storage is used to call this method automatically directly before a node will be * removed. * @throw mitk::Exception Throws an exception if something is wrong, e.g. if the number of observers differs from * the * number of nodes. */ void DataStorageRemovedNode(const DataNode *removedNode = nullptr); /** @brief change notifications from mitkLevelWindowProperty */ void OnPropertyModified(const itk::EventObject &e); Image *GetCurrentImage(); ///< return the currently active image /** * @return Returns the current number of observers which are registered in this object. * @throw mitk::Exception Throws an exception if the number of observers differs from * the number of relevant objects * which means that something is wrong. * */ int GetNumberOfObservers(); /** * returns all nodes in the DataStorage that have the following properties: * "visible" == true, "binary" == false, "levelwindow", and DataType == Image */ DataStorage::SetOfObjects::ConstPointer GetRelevantNodes(); protected: LevelWindowManager(); ~LevelWindowManager() override; DataStorage::Pointer m_DataStorage; - LevelWindowProperty::Pointer m_LevelWindowProperty; ///< pointer to the LevelWindowProperty of the current image + /// Pointer to the LevelWindowProperty of the current image. + LevelWindowProperty::Pointer m_LevelWindowProperty; + typedef std::pair PropDataPair; - typedef std::map ObserverToPropertyMap; - - ObserverToPropertyMap - m_PropObserverToNode; ///< map to hold observer IDs to every visible property of DataNode�s BaseProperty - ObserverToPropertyMap - m_PropObserverToNode2; ///< map to hold observer IDs to every layer property of DataNode�s BaseProperty - ObserverToPropertyMap m_PropObserverToNode3; ///< map to hold observer IDs to every Image Rendering.Mode property of - /// DataNode�s BaseProperty - ObserverToPropertyMap - m_PropObserverToNode4; ///< map to hold observer IDs to every Image.Displayed Component property - /// of DataNode�s BaseProperty - ObserverToPropertyMap - m_PropObserverToNode5; ///< map to hold observer IDs to every image for level window property of - /// DataNode�s BaseProperty - - void UpdateObservers(); ///< updates the internal observer list. Ignores nodes which are marked to be deleted in the - /// variable m_NodeMarkedToDelete - void ClearPropObserverLists(); ///< internal help method to clear both lists/maps. - void CreatePropObserverLists(); ///< internal help method to create both lists/maps. - const mitk::DataNode *m_NodeMarkedToDelete; ///< this variable holds a data node which will be deleted from the - /// datastorage immedeately (if there is one, nullptr otherways) + typedef std::map ObserverToPropertyValueMap; + /// Map to hold observer IDs to every "visible" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToVisibleProperty; + /// Map to hold observer IDs to every "layer" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToLayerProperty; + /// Map to hold observer IDs to every "Image Rendering.Mode" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToRenderingModeProperty; + /// Map to hold observer IDs to every "Image.Displayed Component" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToDisplayedComponentProperty; + /// Map to hold observer IDs to every "imageForLevelWindow" property of DataNode's BaseProperty. + ObserverToPropertyValueMap m_ObserverToLevelWindowImageProperty; + + /// Updates the internal observer list. + /// Ignores nodes which are marked to be deleted in the variable m_NodeMarkedToDelete. + void UpdateObservers(); + /// Internal help method to clear both lists/maps. + void ClearPropObserverLists(); + /// Internal help method to create both lists/maps. + void CreatePropObserverLists(); + /// This variable holds a data node which will be deleted from the datastorage immediately + /// Nullptr, if there is no data node to be deleted. + const DataNode *m_NodeMarkedToDelete; bool m_AutoTopMost; unsigned long m_ObserverTag; bool m_IsObserverTagSet; unsigned long m_PropertyModifiedTag; Image *m_CurrentImage; bool m_IsPropertyModifiedTagSet; - bool m_SettingImgForLvlWinProp; + bool m_LevelWindowMutex; }; } -#endif + +#endif // MITKLEVELWINDOWMANAGER_H diff --git a/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp b/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp index 08c201f25f..cc0bf7fc09 100644 --- a/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp +++ b/Modules/Core/src/DataManagement/mitkLevelWindowManager.cpp @@ -1,624 +1,629 @@ /*=================================================================== 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 "mitkLevelWindowManager.h" #include "mitkDataStorage.h" #include "mitkImage.h" #include "mitkMessage.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include "mitkRenderingModeProperty.h" #include mitk::LevelWindowManager::LevelWindowManager() - : m_DataStorage(nullptr), - m_LevelWindowProperty(nullptr), - m_AutoTopMost(true), - m_IsObserverTagSet(false), - m_CurrentImage(nullptr), - m_IsPropertyModifiedTagSet(false), - m_SettingImgForLvlWinProp(false) + : m_DataStorage(nullptr) + , m_LevelWindowProperty(nullptr) + , m_AutoTopMost(true) + , m_IsObserverTagSet(false) + , m_CurrentImage(nullptr) + , m_IsPropertyModifiedTagSet(false) + , m_LevelWindowMutex(false) { } mitk::LevelWindowManager::~LevelWindowManager() { if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); m_DataStorage = nullptr; } if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } // clear both observer maps this->ClearPropObserverLists(); } -void mitk::LevelWindowManager::SetDataStorage(mitk::DataStorage *ds) +void mitk::LevelWindowManager::SetDataStorage(DataStorage *ds) { if (ds == nullptr) return; /* remove listeners of old DataStorage */ if (m_DataStorage.IsNotNull()) { m_DataStorage->AddNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.RemoveListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); } /* register listener for new DataStorage */ m_DataStorage = ds; // register m_DataStorage->AddNodeEvent.AddListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageAddedNode)); m_DataStorage->RemoveNodeEvent.AddListener( - MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); + MessageDelegate1(this, &LevelWindowManager::DataStorageRemovedNode)); this->DataStorageAddedNode(); // update us with new DataStorage } void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject &) { Modified(); } -void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode *removedNode) +void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode/* = nullptr*/) { m_AutoTopMost = autoTopMost; - if (m_AutoTopMost == false) + if (false == m_AutoTopMost) + { return; + } if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } - /* search topmost image */ + // find topmost image in the data storage if (m_DataStorage.IsNull()) { itkExceptionMacro("DataStorage not set"); } + DataNode::Pointer topLevelNode; int maxLayer = itk::NumericTraits::min(); m_LevelWindowProperty = nullptr; - mitk::DataNode::Pointer topLevelNode; - - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - mitk::DataNode::Pointer node = it->Value(); + DataNode::Pointer node = it->Value(); if (node.IsNull() || (removedNode != nullptr && node == removedNode)) continue; - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; if (node->IsVisible(nullptr) == false) continue; int layer = 0; node->GetIntProperty("layer", layer); if (layer < maxLayer) continue; - mitk::LevelWindowProperty::Pointer levelWindowProperty = - dynamic_cast(node->GetProperty("levelwindow")); + LevelWindowProperty::Pointer levelWindowProperty = + dynamic_cast(node->GetProperty("levelwindow")); if (levelWindowProperty.IsNull()) continue; - int nonLvlWinMode1 = mitk::RenderingModeProperty::LOOKUPTABLE_COLOR; - int nonLvlWinMode2 = mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR; + int nonLvlWinMode1 = RenderingModeProperty::LOOKUPTABLE_COLOR; + int nonLvlWinMode2 = RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR; - mitk::RenderingModeProperty::Pointer mode = - dynamic_cast(node->GetProperty("Image Rendering.Mode")); + RenderingModeProperty::Pointer mode = + dynamic_cast(node->GetProperty("Image Rendering.Mode")); if (mode.IsNotNull()) { int currMode = mode->GetRenderingMode(); if (currMode == nonLvlWinMode1 || currMode == nonLvlWinMode2) { continue; } } else continue; m_LevelWindowProperty = levelWindowProperty; - m_CurrentImage = dynamic_cast(node->GetData()); + m_CurrentImage = dynamic_cast(node->GetData()); topLevelNode = node; maxLayer = layer; } if (topLevelNode.IsNotNull()) { - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; topLevelNode->SetBoolProperty("imageForLevelWindow", true); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; } this->SetLevelWindowProperty(m_LevelWindowProperty); if (m_LevelWindowProperty.IsNull()) { Modified(); } // else SetLevelWindowProperty will call Modified(); } -// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property. void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty) { if (levelWindowProperty.IsNull()) + { return; + } - /* search image than belongs to the property */ - typedef mitk::DataStorage::SetOfObjects NodeSetType; - NodeSetType::ConstPointer nodes = m_DataStorage->GetAll(); - NodeSetType::ConstIterator it = nodes->Begin(); + // find data node that belongs to the property + DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); mitk::DataNode::Pointer propNode = nullptr; - while (it != nodes->End()) + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - mitk::DataNode::Pointer node = it.Value(); - mitk::LevelWindowProperty::Pointer prop = - dynamic_cast(node->GetProperty("levelwindow")); - if (prop == levelWindowProperty) + DataNode::Pointer node = it.Value(); + LevelWindowProperty::Pointer property = dynamic_cast(node->GetProperty("levelwindow")); + if (property == levelWindowProperty) { propNode = node; } else { - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; node->SetBoolProperty("imageForLevelWindow", false); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; } - - ++it; } if (propNode.IsNull()) { - mitkThrow() << "No Image in DataStorage that belongs to LevelWindow property" << m_LevelWindowProperty; + mitkThrow() << "No Image in the data storage that belongs to level-window property " << m_LevelWindowProperty; } if (m_IsPropertyModifiedTagSet) // remove listener for old property { m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag); m_IsPropertyModifiedTagSet = false; } m_LevelWindowProperty = levelWindowProperty; itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); // register listener for new property command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified); m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver(itk::ModifiedEvent(), command); m_IsPropertyModifiedTagSet = true; - m_CurrentImage = dynamic_cast(propNode->GetData()); + m_CurrentImage = dynamic_cast(propNode->GetData()); - m_SettingImgForLvlWinProp = true; + m_LevelWindowMutex = true; propNode->SetBoolProperty("imageForLevelWindow", true); - m_SettingImgForLvlWinProp = false; + m_LevelWindowMutex = false; this->Modified(); } // returns the current mitkLevelWindowProperty object from the image that is affected by changes mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty() { return m_LevelWindowProperty; } // returns Level/Window values for the current image const mitk::LevelWindow &mitk::LevelWindowManager::GetLevelWindow() { if (m_LevelWindowProperty.IsNotNull()) { return m_LevelWindowProperty->GetLevelWindow(); } else { itkExceptionMacro("No LevelWindow available!"); } } // sets new Level/Window values and informs all listeners about changes -void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow &levelWindow) +void mitk::LevelWindowManager::SetLevelWindow(const LevelWindow &levelWindow) { if (m_LevelWindowProperty.IsNotNull()) { m_LevelWindowProperty->SetLevelWindow(levelWindow); } this->Modified(); } -void mitk::LevelWindowManager::DataStorageAddedNode(const mitk::DataNode *) +void mitk::LevelWindowManager::DataStorageAddedNode(const DataNode *) { // update observers with new data storage UpdateObservers(); // Initialize LevelWindowsManager to new image SetAutoTopMostImage(true); // check if everything is still ok - if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || - (m_PropObserverToNode2.size() != this->GetRelevantNodes()->size())) + if ((m_ObserverToVisibleProperty.size() != m_ObserverToLayerProperty.size()) || + (m_ObserverToLayerProperty.size() != this->GetRelevantNodes()->size())) { mitkThrow() << "Wrong number of observers in Level Window Manager!"; } } -void mitk::LevelWindowManager::DataStorageRemovedNode(const mitk::DataNode *removedNode) +void mitk::LevelWindowManager::DataStorageRemovedNode(const DataNode *removedNode) { // first: check if deleted node is part of relevant nodes. If not, abort method because there is no need change // anything. if ((this->GetRelevantNodes()->size() == 0)) return; bool removedNodeIsRelevant = false; /* Iterator code: is crashing, don't know why... so using for loop - for (mitk::DataStorage::SetOfObjects::ConstIterator it = this->GetRelevantNodes()->Begin(); + for (DataStorage::SetOfObjects::ConstIterator it = this->GetRelevantNodes()->Begin(); it != this->GetRelevantNodes()->End(); ++it) {if (it->Value() == removedNode) {removedNodeIsRelevant=true;}}*/ for (unsigned int i = 0; i < this->GetRelevantNodes()->size(); i++) { if (this->GetRelevantNodes()->at(i) == removedNode) { removedNodeIsRelevant = true; } } if (!removedNodeIsRelevant) return; // remember node which will be removed m_NodeMarkedToDelete = removedNode; // update observers UpdateObservers(); - /* search image than belongs to the property */ + // search image that belongs to the property if (m_LevelWindowProperty.IsNull()) { SetAutoTopMostImage(true, removedNode); } else { - mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); - mitk::DataNode *n = m_DataStorage->GetNode(p2); - if (n == nullptr || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true + NodePredicateProperty::Pointer property = NodePredicateProperty::New("levelwindow", m_LevelWindowProperty); + DataNode *n = m_DataStorage->GetNode(property); + if (n == nullptr || m_AutoTopMost) // if node was deleted, change our behavior to AutoTopMost, if AutoTopMost is true // change level window to topmost node { SetAutoTopMostImage(true, removedNode); } } // reset variable m_NodeMarkedToDelete = nullptr; // check if everything is still ok - if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || - (m_PropObserverToNode2.size() != (this->GetRelevantNodes()->size() - 1))) + if ((m_ObserverToVisibleProperty.size() != m_ObserverToLayerProperty.size()) || + (m_ObserverToLayerProperty.size() != (this->GetRelevantNodes()->size() - 1))) { mitkThrow() << "Wrong number of observers in Level Window Manager!"; } } void mitk::LevelWindowManager::UpdateObservers() { this->ClearPropObserverLists(); // remove old observers CreatePropObserverLists(); // create new observer lists } int mitk::LevelWindowManager::GetNumberOfObservers() { - return m_PropObserverToNode.size(); + return m_ObserverToVisibleProperty.size(); } mitk::DataStorage *mitk::LevelWindowManager::GetDataStorage() { return m_DataStorage.GetPointer(); } -// true if changes on slider or line-edits will affect always the topmost layer image -bool mitk::LevelWindowManager::isAutoTopMost() +bool mitk::LevelWindowManager::IsAutoTopMost() { return m_AutoTopMost; } -void mitk::LevelWindowManager::RecaluclateLevelWindowForSelectedComponent(const itk::EventObject &event) +bool mitk::LevelWindowManager::IsSelectedImages() { - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + return m_SelectedImages; +} + +void mitk::LevelWindowManager::RecalculateLevelWindowForSelectedComponent(const itk::EventObject &event) +{ + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - mitk::DataNode::Pointer node = it->Value(); + DataNode::Pointer node = it->Value(); if (node.IsNull()) continue; bool isSelected = false; node->GetBoolProperty("selected", isSelected); if (isSelected) { - mitk::LevelWindow selectedLevelWindow; + LevelWindow selectedLevelWindow; node->GetLevelWindow(selectedLevelWindow); // node is an image node because of predicates - auto *image = dynamic_cast(node->GetData()); + auto *image = dynamic_cast(node->GetData()); int displayedComponent = 0; if (image && (node->GetIntProperty("Image.Displayed Component", displayedComponent))) { // we found a selected image with a displayed component // let's recalculate the levelwindow for this. selectedLevelWindow.SetAuto(image, true, true, static_cast(displayedComponent)); node->SetLevelWindow(selectedLevelWindow); } } - mitk::LevelWindow levelWindow; + LevelWindow levelWindow; node->GetLevelWindow(levelWindow); } this->Update(event); } -void mitk::LevelWindowManager::Update(const itk::EventObject &) // visible property of a image has changed +void mitk::LevelWindowManager::Update(const itk::EventObject &) { - if (m_SettingImgForLvlWinProp) // no mutex, should still help + if (m_LevelWindowMutex) // no mutex, should still help { return; } if (m_AutoTopMost) { SetAutoTopMostImage(true); return; } + else if (m_SelectedImages) + { + SetSelectedImages(true); + return; + } int maxVisibleLayer = itk::NumericTraits::min(); - mitk::DataNode::Pointer highestVisible = nullptr; - std::vector visProbNodes; + DataNode::Pointer highestVisible = nullptr; + std::vector visProbNodes; - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { - mitk::DataNode::Pointer node = it->Value(); + DataNode::Pointer node = it->Value(); if (node.IsNull()) { continue; } bool visible = node->IsVisible(nullptr); - - if (node->IsVisible(nullptr)) + if (visible) { int layer = -1; node->GetIntProperty("layer", layer); if (layer > maxVisibleLayer) { maxVisibleLayer = layer; highestVisible = node; } - } - - bool prop = false; - node->GetBoolProperty("imageForLevelWindow", prop); - if (prop && visible) - { - visProbNodes.push_back(node); + bool prop = false; + node->GetBoolProperty("imageForLevelWindow", prop); + if (prop) + { + visProbNodes.push_back(node); + } } } int numVisProbNodes = visProbNodes.size(); if (numVisProbNodes > 2) { MITK_ERROR << "Error: not more than two visible nodes are expected to have the imageForLevelWindow property set at " "any point."; } else if (numVisProbNodes == 2) { - for (std::vector::const_iterator it = visProbNodes.begin(); it != visProbNodes.end(); ++it) + for (std::vector::const_iterator it = visProbNodes.begin(); it != visProbNodes.end(); ++it) { - mitk::LevelWindowProperty::Pointer newProp = - dynamic_cast((*it)->GetProperty("levelwindow")); + LevelWindowProperty::Pointer newProp = + dynamic_cast((*it)->GetProperty("levelwindow")); if (newProp != m_LevelWindowProperty) { this->SetLevelWindowProperty(newProp); return; } } } else if (numVisProbNodes == 1) { - mitk::LevelWindowProperty::Pointer newProp = - dynamic_cast(visProbNodes[0]->GetProperty("levelwindow")); + LevelWindowProperty::Pointer newProp = + dynamic_cast(visProbNodes[0]->GetProperty("levelwindow")); if (newProp != m_LevelWindowProperty) { this->SetLevelWindowProperty(newProp); return; } } else if (highestVisible) { - mitk::LevelWindowProperty::Pointer lvlProp = - dynamic_cast(highestVisible->GetProperty("levelwindow")); + LevelWindowProperty::Pointer lvlProp = + dynamic_cast(highestVisible->GetProperty("levelwindow")); this->SetLevelWindowProperty(lvlProp); } else { Modified(); } } mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes() { if (m_DataStorage.IsNull()) - return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New()); // return empty set - - mitk::NodePredicateProperty::Pointer notBinary = - mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false)); - mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", nullptr); - - mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); - mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage"); - mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage"); - mitk::NodePredicateDataType::Pointer isOdfImage = mitk::NodePredicateDataType::New("OdfImage"); - mitk::NodePredicateDataType::Pointer isShImage = mitk::NodePredicateDataType::New("ShImage"); - mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New(); + return DataStorage::SetOfObjects::ConstPointer(DataStorage::SetOfObjects::New()); // return empty set + + NodePredicateProperty::Pointer notBinary = NodePredicateProperty::New("binary", BoolProperty::New(false)); + NodePredicateProperty::Pointer hasLevelWindow = NodePredicateProperty::New("levelwindow", nullptr); + + NodePredicateDataType::Pointer isImage = NodePredicateDataType::New("Image"); + NodePredicateDataType::Pointer isDImage = NodePredicateDataType::New("DiffusionImage"); + NodePredicateDataType::Pointer isTImage = NodePredicateDataType::New("TensorImage"); + NodePredicateDataType::Pointer isOdfImage = NodePredicateDataType::New("OdfImage"); + NodePredicateDataType::Pointer isShImage = NodePredicateDataType::New("ShImage"); + NodePredicateOr::Pointer predicateTypes = NodePredicateOr::New(); predicateTypes->AddPredicate(isImage); predicateTypes->AddPredicate(isDImage); predicateTypes->AddPredicate(isTImage); predicateTypes->AddPredicate(isOdfImage); predicateTypes->AddPredicate(isShImage); - mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New(); + NodePredicateAnd::Pointer predicate = NodePredicateAnd::New(); predicate->AddPredicate(notBinary); predicate->AddPredicate(hasLevelWindow); predicate->AddPredicate(predicateTypes); - mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset(predicate); + DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset(predicate); return relevantNodes; } mitk::Image *mitk::LevelWindowManager::GetCurrentImage() { return m_CurrentImage; } void mitk::LevelWindowManager::ClearPropObserverLists() { - for (auto iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); ++iter) + for (auto iter = m_ObserverToVisibleProperty.begin(); iter != m_ObserverToVisibleProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode.clear(); + m_ObserverToVisibleProperty.clear(); - for (auto iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); - ++iter) + for (auto iter = m_ObserverToLayerProperty.begin(); iter != m_ObserverToLayerProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode2.clear(); + m_ObserverToLayerProperty.clear(); - for (auto iter = m_PropObserverToNode3.begin(); iter != m_PropObserverToNode3.end(); - ++iter) + for (auto iter = m_ObserverToRenderingModeProperty.begin(); iter != m_ObserverToRenderingModeProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode3.clear(); + m_ObserverToRenderingModeProperty.clear(); - for (auto iter = m_PropObserverToNode4.begin(); iter != m_PropObserverToNode4.end(); - ++iter) + for (auto iter = m_ObserverToDisplayedComponentProperty.begin(); iter != m_ObserverToDisplayedComponentProperty.end(); ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode4.clear(); + m_ObserverToDisplayedComponentProperty.clear(); + + for (auto iter = m_ObserverToLevelWindowImageProperty.begin(); iter != m_ObserverToLevelWindowImageProperty.end(); ++iter) + { + (*iter).second->RemoveObserver((*iter).first.first); + (*iter).second = nullptr; + } + m_ObserverToLevelWindowImageProperty.clear(); - for (auto iter = m_PropObserverToNode5.begin(); iter != m_PropObserverToNode5.end(); - ++iter) { (*iter).second->RemoveObserver((*iter).first.first); (*iter).second = nullptr; } - m_PropObserverToNode5.clear(); } void mitk::LevelWindowManager::CreatePropObserverLists() { if (m_DataStorage.IsNull()) // check if data storage is set { itkExceptionMacro("DataStorage not set"); } /* add observers for all relevant nodes */ - mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) + DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes(); + for (DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete)) { continue; } /* register listener for changes in visible property */ itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &LevelWindowManager::Update); unsigned long visIdx = it->Value()->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); - m_PropObserverToNode[PropDataPair(visIdx, it->Value())] = it->Value()->GetProperty("visible"); + m_ObserverToVisibleProperty[PropDataPair(visIdx, it->Value())] = it->Value()->GetProperty("visible"); /* register listener for changes in layer property */ itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction(this, &LevelWindowManager::Update); unsigned long layerIdx = it->Value()->GetProperty("layer")->AddObserver(itk::ModifiedEvent(), command2); - m_PropObserverToNode2[PropDataPair(layerIdx, it->Value())] = it->Value()->GetProperty("layer"); + m_ObserverToLayerProperty[PropDataPair(layerIdx, it->Value())] = it->Value()->GetProperty("layer"); /* register listener for changes in layer property */ itk::ReceptorMemberCommand::Pointer command3 = itk::ReceptorMemberCommand::New(); command3->SetCallbackFunction(this, &LevelWindowManager::Update); - mitk::BaseProperty::Pointer imageRenderingMode = it->Value()->GetProperty("Image Rendering.Mode"); + BaseProperty::Pointer imageRenderingMode = it->Value()->GetProperty("Image Rendering.Mode"); if (imageRenderingMode.IsNotNull()) { unsigned long rendIdx = imageRenderingMode->AddObserver(itk::ModifiedEvent(), command3); - m_PropObserverToNode3[PropDataPair(rendIdx, it->Value())] = imageRenderingMode.GetPointer(); + m_ObserverToRenderingModeProperty[PropDataPair(rendIdx, it->Value())] = imageRenderingMode.GetPointer(); } itk::ReceptorMemberCommand::Pointer command4 = itk::ReceptorMemberCommand::New(); - command4->SetCallbackFunction(this, &LevelWindowManager::RecaluclateLevelWindowForSelectedComponent); - mitk::BaseProperty::Pointer displayedImageComponent = it->Value()->GetProperty("Image.Displayed Component"); + command4->SetCallbackFunction(this, &LevelWindowManager::RecalculateLevelWindowForSelectedComponent); + BaseProperty::Pointer displayedImageComponent = it->Value()->GetProperty("Image.Displayed Component"); if (displayedImageComponent.IsNotNull()) { unsigned long dispIdx = displayedImageComponent->AddObserver(itk::ModifiedEvent(), command4); - m_PropObserverToNode4[PropDataPair(dispIdx, it->Value())] = displayedImageComponent.GetPointer(); + m_ObserverToDisplayedComponentProperty[PropDataPair(dispIdx, it->Value())] = displayedImageComponent.GetPointer(); } itk::ReceptorMemberCommand::Pointer command5 = itk::ReceptorMemberCommand::New(); command5->SetCallbackFunction(this, &LevelWindowManager::Update); - mitk::BaseProperty::Pointer imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); + BaseProperty::Pointer imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); if (imgForLvlWin.IsNull()) { it->Value()->SetBoolProperty("imageForLevelWindow", false); imgForLvlWin = it->Value()->GetProperty("imageForLevelWindow"); } unsigned long lvlWinIdx = imgForLvlWin->AddObserver(itk::ModifiedEvent(), command5); - m_PropObserverToNode5[PropDataPair(lvlWinIdx, it->Value())] = it->Value()->GetProperty("imageForLevelWindow"); + m_ObserverToLevelWindowImageProperty[PropDataPair(lvlWinIdx, it->Value())] = it->Value()->GetProperty("imageForLevelWindow"); + } } diff --git a/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h b/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h index 6c1a5af5f0..8fae9be780 100644 --- a/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h +++ b/Modules/QtWidgets/include/QmitkLevelWindowWidgetContextMenu.h @@ -1,121 +1,120 @@ /*=================================================================== 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 QMITKLEVELWINDOWWIDGETCONTEXTMENU_H #define QMITKLEVELWINDOWWIDGETCONTEXTMENU_H #include #include #include #include /** * \ingroup QmitkModule * \brief Provides a contextmenu for Level/Window functionality. * * Either creates * a new contextmenu with standard functions or adds Level/Window standard * functions to an predefined contextmenu. */ class MITKQTWIDGETS_EXPORT QmitkLevelWindowWidgetContextMenu : public QWidget { Q_OBJECT public: /// constructor QmitkLevelWindowWidgetContextMenu(QWidget *parent, Qt::WindowFlags f = nullptr); ~QmitkLevelWindowWidgetContextMenu() override; /*! * data structure which reads and writes presets defined in a XML-file */ mitk::LevelWindowPreset *m_LevelWindowPreset; /*! * data structure which stores the values manipulated * by a QmitkLevelWindowWidgetContextMenu */ mitk::LevelWindow m_LevelWindow; /// submenu with all presets for contextmenu QMenu *m_PresetSubmenu; /// submenu with all images for contextmenu QMenu *m_ImageSubmenu; /// pointer to the object which manages all Level/Window changes on images and holds the LevelWindowProperty /// of the current image mitk::LevelWindowManager *m_Manager; /// map to hold all image-properties, one can get the image which is selected in the contextmenu /// with the QAction representing the image for the contextmenu std::map m_Images; /*! * returns the contextmenu with standard functions for Level/Window * * input is a prefilled contextmenu to which standard functions will be added */ - void getContextMenu(QMenu *contextmenu); + void GetContextMenu(QMenu *contextMenu); /// returns the contextmenu with standard functions for Level/Window - void getContextMenu(); + void GetContextMenu(); /// lets this object know about the LevelWindowManager to get all images and tell about changes - void setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); + void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); protected: - /// ID of preset selected in contextmenu - QAction *m_PresetAction; - /// ID of image selected in contextmenu - QAction *m_ImageAction; + QAction *m_PresetAction; + QAction *m_AutoTopmostAction; -protected slots: +protected Q_SLOTS: /// sets level and window value of the current image to the values defined for the selected preset - void setPreset(QAction *presetAction); + void OnSetPreset(const QAction *presetAction); /// calls the mitkLevelWindow SetAuto method with guessByCentralSlice false, so that the greyvalues from whole image /// will be considered - void useOptimizedLevelWindow(); + void OnUseOptimizedLevelWindow(); /// calls the mitkLevelWindow SetToImageRange method, so that the greyvalues from whole image will be used - void useAllGreyvaluesFromImage(); + void OnUseAllGreyvaluesFromImage(); /// sets the level window slider to be fixed - void setFixed(); + void OnSetFixed(); /// adds a new Preset for presets-contextmenu - void addPreset(); + void OnAddPreset(); /// resets the current images Level/Window to its default values - void setDefaultLevelWindow(); + void OnSetDefaultLevelWindow(); /// resets the current images scalerange to its default values - void setDefaultScaleRange(); + void OnSetDefaultScaleRange(); /// changes the current images scalerange - void changeScaleRange(); + void OnChangeScaleRange(); /// sets the selected image or the topmost layer image to the new current image - void setImage(QAction *imageAction); + void OnSetImage(QAction *imageAction); /// sets the window to its maximum Size to fit the scalerange - void setMaximumWindow(); + void OnSetMaximumWindow(); }; -#endif + +#endif // QMITKLEVELWINDOWWIDGETCONTEXTMENU_H diff --git a/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h b/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h index 429238a86c..a01af09448 100644 --- a/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkLineEditLevelWindowWidget.h @@ -1,97 +1,97 @@ /*=================================================================== 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 QMITKLINEEDITLEVELWINDOWWIDGET -#define QMITKLINEEDITLEVELWINDOWWIDGET +#ifndef QMITKLINEEDITLEVELWINDOWWIDGET_H +#define QMITKLINEEDITLEVELWINDOWWIDGET_H #include -#include - +// mitk core #include +// qt +#include + class QmitkLevelWindowWidgetContextMenu; class QLineEdit; /** * \ingroup QmitkModule * \brief Provides a widget with two lineedit fields, one to change the * window value of the current image and one to change the level value of * the current image. */ class MITKQTWIDGETS_EXPORT QmitkLineEditLevelWindowWidget : public QWidget { Q_OBJECT public: /// constructor QmitkLineEditLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); /// destructor ~QmitkLineEditLevelWindowWidget() override; /// inputfield for level value QLineEdit *m_LevelInput; /// inputfield for window value QLineEdit *m_WindowInput; /*! * data structure which stores the values manipulated * by a QmitkLineEditLevelWindowWidget */ mitk::LevelWindow m_LevelWindow; /// manager who is responsible to collect and deliver changes on Level/Window mitk::LevelWindowManager::Pointer m_Manager; /// sets the manager who is responsible to collect and deliver changes on Level/Window - void setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); + void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); /// sets the DataStorage which holds all image-nodes void SetDataStorage(mitk::DataStorage *ds); /// returns the manager who is responsible to collect and deliver changes on Level/Window mitk::LevelWindowManager *GetManager(); private: /// creates the contextmenu for this widget from class QmitkLevelWindowWidgetContextMenu void contextMenuEvent(QContextMenuEvent *) override; /// change notifications from the mitkLevelWindowManager void OnPropertyModified(const itk::EventObject &e); -public slots: +public Q_SLOTS: - /// called when return is pressed in levelinput field + /** @brief Read the levelInput and change level and slider when the button "ENTER" was pressed + * in the windowInput-LineEdit. + */ void SetLevelValue(); - - /// called when return is pressed in windowinput field + /** @brief Read the windowInput and change window and slider when the button "ENTER" was pressed + * in the windowInput-LineEdit. + */ void SetWindowValue(); - // validator to accept only possible values for Level/Window in lineedits - // void setValidator(); - protected: unsigned long m_ObserverTag; bool m_IsObserverTagSet; - /*! - * data structure which creates the contextmenu for QmitkLineEditLevelWindowWidget - */ QmitkLevelWindowWidgetContextMenu *m_Contextmenu; }; -#endif // QMITKLINEEDITLEVELWINDOWWIDGET + +#endif // QMITKLINEEDITLEVELWINDOWWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h b/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h index 32b14887ab..624f8319ba 100644 --- a/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkSliderLevelWindowWidget.h @@ -1,193 +1,192 @@ /*=================================================================== 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 QMITKSLIDERLEVELWINDOW_WIDGET -#define QMITKSLIDERLEVELWINDOW_WIDGET +#ifndef QMITKSLIDERLEVELWINDOWWIDGET_H +#define QMITKSLIDERLEVELWINDOWWIDGET_H #include #include #include class QmitkLevelWindowWidgetContextMenu; /** * \ingroup QmitkModule * * \brief Provides a widget with a slider to change the level and * window value of the current image. * * This documentation actually refers to the QmitkLevelWindowWidget * and is only put in this class due to technical issues (should be * moved later). * * The QmitkLevelWindowWidget is a kind of container for a * QmitkSliderLevelWindowWidget (this is the cyan bar above the text * input fields) and a QmitkLineEditLevelWindowWidget (with two text * input fields). It holds a reference to a mitk::LevelWindowManager * variable, which keeps the LevelWindowProperty of the currently * selected image. Level/Window is manipulated by the text inputs and * the Slider to adjust brightness/contrast of a single image. All * changes on the slider or in the text input fields affect the current * image by giving new values to LevelWindowManager. LevelWindowManager * then sends a signal to tell other listeners about changes. * * Which image is changed is determined by mitkLevelWindowManager. If * m_AutoTopMost is true, always the topmost image in data tree (layer * property) is affected by changes. The image which is affected by * changes can also be changed by QmitkLevelWindowWidgetContextMenu, * the context menu for QmitkSliderLevelWindowWidget and * QmitkLineEditLevelWindowWidget. There you have the possibility to * set a certain image or always the topmost image in the data tree * (layer property) to be affected by changes. * * The internal mitk::LevelWindow variable contains a range that is * valid for a given image. It should not be possible to move the * level/window parameters outside this range. The range can be changed * and reset to its default values by QmitkLevelWindowWidgetContextMenu, * the context menu for QmitkSliderLevelWindowWidget and * QmitkLineEditLevelWindowWidget. * * Now for the behaviour of the text inputs: The upper one contains the * value of the level (brightness), the lower one shows the window (contrast). * * The behaviour of the cyan bar is more obvious: the scale in the * background shows the valid range. The cyan bar in front displays the * currently selected level/window setting. You can change the level by * dragging the bar with the left mouse button or clicking somewhere inside * the scalerange with the left mouse button. The window is changed by * moving the mouse on the upper or lower bound of the bar until the cursor * becomes an vertical double-arrowed symbol. Then you can change the * windowsize by clicking the left mouse button and move the mouse upwards * or downwards. The bar becomes greater upwards as well as downwards. If * you want to change the size of the window in only one direction you * have to press the CTRL-key while doing the same as mentioned above. * This information is also presented by a tooltip text when moving the * mouse on the upper or lower bound of the bar. */ class MITKQTWIDGETS_EXPORT QmitkSliderLevelWindowWidget : public QWidget { Q_OBJECT public: /// constructor QmitkSliderLevelWindowWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); /// destructor ~QmitkSliderLevelWindowWidget() override; - /*! - * data structure which stores the values manipulated - * by a QmitkSliderLevelWindowWidget - */ - mitk::LevelWindow m_LevelWindow; - - /// manager who is responsible to collect and deliver changes on Level/Window - mitk::LevelWindowManager::Pointer m_Manager; - /// sets the manager who is responsible to collect and deliver changes on Level/Window - void setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); + void SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager); /// sets the DataStorage which holds all image-nodes - void setDataStorage(mitk::DataStorage *ds); + void SetDataStorage(mitk::DataStorage *ds); /// returns the manager who is responsible to collect and deliver changes on Level/Window mitk::LevelWindowManager *GetManager(); + mitk::LevelWindow m_LevelWindow; + + /// manager who is responsible to collect and deliver changes on Level/Window + mitk::LevelWindowManager::Pointer m_Manager; + private: - /// creates the contextmenu for this widget from class QmitkLevelWindowWidgetContextMenu + /// creates the context menu for this widget from class QmitkLevelWindowWidgetContextMenu void contextMenuEvent(QContextMenuEvent *) override; /// change notifications from the mitkLevelWindowManager void OnPropertyModified(const itk::EventObject &e); protected: /// recalculate the size and position of the slider bar - virtual void update(); + virtual void Update(); /*! * helper for drawing the component */ QRect m_Rect; /*! * helper for drawing the component */ QPoint m_StartPos; bool m_Resize; bool m_Bottom; bool m_MouseDown; bool m_Leftbutton; bool m_CtrlPressed; int m_MoveHeight; bool m_ScaleVisible; QRect m_LowerBound; QRect m_UpperBound; unsigned long m_ObserverTag; bool m_IsObserverTagSet; QFont m_Font; /*! - * data structure which creates the contextmenu for QmitkLineEditLevelWindowWidget + * data structure which creates the context menu for QmitkLineEditLevelWindowWidget */ QmitkLevelWindowWidgetContextMenu *m_Contextmenu; /*! * repaint the slider and the scale */ void paintEvent(QPaintEvent *e) override; /*! - * method implements the component behaviour + * method implements the component behavior * * checks if cursor is on upper or lower bound of slider bar and changes cursor symbol * - * checks if left mouse button is pressed and if CTRL is pressed and changes sliderbar in movedirection accordingly + * checks if left mouse button is pressed and if CTRL is pressed and changes sliderbar in move-direction accordingly */ void mouseMoveEvent(QMouseEvent *mouseEvent) override; void enterEvent(QEvent *event) override; /*! * registers events when a mousebutton is pressed * * if leftbutton is pressed m_Leftbutton is set to true * * also checks if CTRL is pressed and sets the bool variable m_CtrlPressed */ void mousePressEvent(QMouseEvent *mouseEvent) override; /*! * sets the variable m_MouseDown to false */ void mouseReleaseEvent(QMouseEvent *mouseEvent) override; /*! * causes an update of the sliderbar when resizing the window */ void resizeEvent(QResizeEvent *event) override; -protected slots: +protected Q_SLOTS: - /// hides the scale if "Hide Scale" is selected in contextmenu - void hideScale(); + /** @brief Hide the scale if "Hide Scale" is selected in the context menu + */ + void HideScale(); - /// shows the scale if "Show Scale" is selected in contextmenu - void showScale(); + /** @brief Shows the scale if "Show Scale" is selected in the context menu + */ + void ShowScale(); }; -#endif // QMITKSLIDERLEVELWINDOW_WIDGET + +#endif // QMITKSLIDERLEVELWINDOWWIDGET_H diff --git a/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp index a70e5b0151..d6805560a9 100644 --- a/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkLevelWindowWidget.cpp @@ -1,37 +1,37 @@ /*=================================================================== 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 "QmitkLevelWindowWidget.h" #include "QmitkSliderLevelWindowWidget.h" QmitkLevelWindowWidget::QmitkLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { this->setupUi(this); m_Manager = mitk::LevelWindowManager::New(); - SliderLevelWindowWidget->setLevelWindowManager(m_Manager.GetPointer()); - LineEditLevelWindowWidget->setLevelWindowManager(m_Manager.GetPointer()); + SliderLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); + LineEditLevelWindowWidget->SetLevelWindowManager(m_Manager.GetPointer()); } void QmitkLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } mitk::LevelWindowManager *QmitkLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); } diff --git a/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp b/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp index 059c0c8189..c02a327120 100644 --- a/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp +++ b/Modules/QtWidgets/src/QmitkLevelWindowWidgetContextMenu.cpp @@ -1,252 +1,286 @@ /*=================================================================== 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 + +// mitk core +#include + +// mitk qt widgets #include "QmitkLevelWindowPresetDefinitionDialog.h" #include "QmitkLevelWindowRangeChangeDialog.h" + +// qt #include -#include -#include QmitkLevelWindowWidgetContextMenu::QmitkLevelWindowWidgetContextMenu(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { m_LevelWindowPreset = mitk::LevelWindowPreset::New(); m_LevelWindowPreset->LoadPreset(); } QmitkLevelWindowWidgetContextMenu::~QmitkLevelWindowWidgetContextMenu() { m_LevelWindowPreset->Delete(); } -void QmitkLevelWindowWidgetContextMenu::setPreset(QAction *presetAction) +void QmitkLevelWindowWidgetContextMenu::OnSetPreset(const QAction *presetAction) { QString item = presetAction->text(); if (!(presetAction == m_PresetAction)) { double dlevel = m_LevelWindowPreset->getLevel(item.toStdString()); double dwindow = m_LevelWindowPreset->getWindow(item.toStdString()); if ((dlevel + dwindow / 2) > m_LevelWindow.GetRangeMax()) { double lowerBound = (dlevel - dwindow / 2); if (!(lowerBound > m_LevelWindow.GetRangeMax())) { dwindow = m_LevelWindow.GetRangeMax() - lowerBound; dlevel = lowerBound + dwindow / 2; } else { dlevel = m_LevelWindow.GetRangeMax() - 1; dwindow = 2; } } else if ((dlevel - dwindow / 2) < m_LevelWindow.GetRangeMin()) { double upperBound = (dlevel + dwindow / 2); if (!(upperBound < m_LevelWindow.GetRangeMin())) { dwindow = m_LevelWindow.GetRangeMin() + upperBound; dlevel = upperBound - dwindow / 2; } else { dlevel = m_LevelWindow.GetRangeMin() + 1; dwindow = 2; } } m_LevelWindow.SetLevelWindow(dlevel, dwindow); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } -void QmitkLevelWindowWidgetContextMenu::setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) +void QmitkLevelWindowWidgetContextMenu::SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) { m_Manager = levelWindowManager; } -void QmitkLevelWindowWidgetContextMenu::addPreset() +void QmitkLevelWindowWidgetContextMenu::OnAddPreset() { QmitkLevelWindowPresetDefinitionDialog addPreset(this); addPreset.setPresets(m_LevelWindowPreset->getLevelPresets(), m_LevelWindowPreset->getWindowPresets(), QString::number((int)m_LevelWindow.GetLevel()), QString::number((int)m_LevelWindow.GetWindow())); if (addPreset.exec()) { m_LevelWindowPreset->newPresets(addPreset.getLevelPresets(), addPreset.getWindowPresets()); } } -void QmitkLevelWindowWidgetContextMenu::setFixed() +void QmitkLevelWindowWidgetContextMenu::OnSetFixed() { m_LevelWindow.SetFixed(!m_LevelWindow.GetFixed()); m_Manager->SetLevelWindow(m_LevelWindow); } -void QmitkLevelWindowWidgetContextMenu::useAllGreyvaluesFromImage() +void QmitkLevelWindowWidgetContextMenu::OnUseAllGreyvaluesFromImage() { m_LevelWindow.SetToImageRange(m_Manager->GetCurrentImage()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::useOptimizedLevelWindow() +void QmitkLevelWindowWidgetContextMenu::OnUseOptimizedLevelWindow() { m_LevelWindow.SetAuto(m_Manager->GetCurrentImage(), false, false); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::setDefaultLevelWindow() +void QmitkLevelWindowWidgetContextMenu::OnSetDefaultLevelWindow() { m_LevelWindow.ResetDefaultLevelWindow(); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::setMaximumWindow() +void QmitkLevelWindowWidgetContextMenu::OnSetMaximumWindow() { m_LevelWindow.SetToMaxWindowSize(); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::setDefaultScaleRange() +void QmitkLevelWindowWidgetContextMenu::OnSetDefaultScaleRange() { m_LevelWindow.ResetDefaultRangeMinMax(); m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), m_LevelWindow.GetWindow()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -void QmitkLevelWindowWidgetContextMenu::changeScaleRange() +void QmitkLevelWindowWidgetContextMenu::OnChangeScaleRange() { QmitkLevelWindowRangeChangeDialog changeRange(this); changeRange.setLowerLimit((mitk::ScalarType)m_LevelWindow.GetRangeMin()); changeRange.setUpperLimit((mitk::ScalarType)m_LevelWindow.GetRangeMax()); if (changeRange.exec()) { m_LevelWindow.SetRangeMinMax(changeRange.getLowerLimit(), changeRange.getUpperLimit()); m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), m_LevelWindow.GetWindow()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } -void QmitkLevelWindowWidgetContextMenu::setImage(QAction *imageAction) +void QmitkLevelWindowWidgetContextMenu::OnSetImage(QAction *imageAction) { - if (imageAction == m_ImageAction) - if (m_Manager->isAutoTopMost() == false) + if (imageAction == m_AutoTopmostAction) + { + if (m_Manager->IsAutoTopMost() == false) + { m_Manager->SetAutoTopMostImage(true); + } else + { m_Manager->SetAutoTopMostImage(false); + } + } else - m_Manager->SetLevelWindowProperty(m_Images[imageAction]); + { + m_Manager->SetLevelWindowProperty(m_Images.at(imageAction)); + } } -void QmitkLevelWindowWidgetContextMenu::getContextMenu(QMenu *contextmenu) +void QmitkLevelWindowWidgetContextMenu::GetContextMenu(QMenu *contextMenu) { + if (nullptr == contextMenu) + { + return; + } + try { m_LevelWindow = m_Manager->GetLevelWindow(); - QMenu *contextMenu = contextmenu; - Q_CHECK_PTR(contextMenu); - // contextMenu->setCheckable(true); - QAction *sliderFixed = contextMenu->addAction(tr("Set Slider Fixed"), this, SLOT(setFixed())); + QAction *sliderFixed = contextMenu->addAction(tr("Set slider fixed"), this, &QmitkLevelWindowWidgetContextMenu::OnSetFixed); sliderFixed->setCheckable(true); sliderFixed->setChecked(m_LevelWindow.IsFixed()); contextMenu->addSeparator(); - contextMenu->addAction(tr("Use whole image grey values"), this, SLOT(useAllGreyvaluesFromImage())); - contextMenu->addAction(tr("Use optimized levelwindow"), this, SLOT(useOptimizedLevelWindow())); + contextMenu->addAction(tr("Use whole image grey values"), this, &QmitkLevelWindowWidgetContextMenu::OnUseAllGreyvaluesFromImage); + contextMenu->addAction(tr("Use optimized level-window"), this, &QmitkLevelWindowWidgetContextMenu::OnUseOptimizedLevelWindow); contextMenu->addSeparator(); - contextMenu->addAction(tr("Set Maximum Window"), this, SLOT(setMaximumWindow())); - contextMenu->addAction(tr("Default Level/Window"), this, SLOT(setDefaultLevelWindow())); + contextMenu->addAction(tr("Set maximum window"), this, &QmitkLevelWindowWidgetContextMenu::OnSetMaximumWindow); + contextMenu->addAction(tr("Default level-window"), this, &QmitkLevelWindowWidgetContextMenu::OnSetDefaultLevelWindow); contextMenu->addSeparator(); - contextMenu->addAction(tr("Change Scale Range"), this, SLOT(changeScaleRange())); - contextMenu->addAction(tr("Default Scale Range"), this, SLOT(setDefaultScaleRange())); + contextMenu->addAction(tr("Change scale range"), this, &QmitkLevelWindowWidgetContextMenu::OnChangeScaleRange); + contextMenu->addAction(tr("Default scale range"), this, &QmitkLevelWindowWidgetContextMenu::OnSetDefaultScaleRange); contextMenu->addSeparator(); m_PresetSubmenu = new QMenu(this); - Q_CHECK_PTR(m_PresetSubmenu); m_PresetSubmenu->setTitle("Presets"); - m_PresetAction = m_PresetSubmenu->addAction(tr("Preset Definition"), this, SLOT(addPreset())); + m_PresetAction = m_PresetSubmenu->addAction(tr("Preset definition"), this, &QmitkLevelWindowWidgetContextMenu::OnAddPreset); m_PresetSubmenu->addSeparator(); std::map preset = m_LevelWindowPreset->getLevelPresets(); for (auto iter = preset.begin(); iter != preset.end(); iter++) { QString item = ((*iter).first.c_str()); m_PresetSubmenu->addAction(item); } - connect(m_PresetSubmenu, SIGNAL(triggered(QAction *)), this, SLOT(setPreset(QAction *))); + + connect(m_PresetSubmenu, &QMenu::triggered, this, &QmitkLevelWindowWidgetContextMenu::OnSetPreset); contextMenu->addMenu(m_PresetSubmenu); contextMenu->addSeparator(); - m_ImageSubmenu = new QMenu(this); m_ImageSubmenu->setTitle("Images"); - // m_ImageSubmenu->setCheckable(true); - m_ImageAction = m_ImageSubmenu->addAction(tr("Set Topmost Image")); - m_ImageAction->setCheckable(true); - if (m_Manager->isAutoTopMost()) - m_ImageAction->setChecked(true); + + // add action for "auto topmost image" action + m_AutoTopmostAction = m_ImageSubmenu->addAction(tr("Set topmost image")); + m_AutoTopmostAction->setCheckable(true); + if (m_Manager->IsAutoTopMost()) + { + m_AutoTopmostAction->setChecked(true); + } + + + // add action for individual images m_ImageSubmenu->addSeparator(); - Q_CHECK_PTR(m_ImageSubmenu); + mitk::DataStorage::SetOfObjects::ConstPointer allObjects = m_Manager->GetRelevantNodes(); for (mitk::DataStorage::SetOfObjects::ConstIterator objectIter = allObjects->Begin(); - objectIter != allObjects->End(); - ++objectIter) + objectIter != allObjects->End(); + ++objectIter) { mitk::DataNode *node = objectIter->Value(); - if (node) + if (nullptr == node) + { + continue; + } + + bool isHelperObject = false; + node->GetBoolProperty("helper object", isHelperObject); + + if (isHelperObject) { - if (node->IsVisible(nullptr) == false) - continue; - mitk::LevelWindowProperty::Pointer levelWindowProperty = - dynamic_cast(node->GetProperty("levelwindow")); - bool isHelperObject = false; - node->GetBoolProperty("helper object", isHelperObject); - if (levelWindowProperty.IsNotNull() && !isHelperObject) + continue; + } + + if (!node->IsVisible(nullptr)) + { + continue; + } + + mitk::LevelWindowProperty::Pointer levelWindowProperty = + dynamic_cast(node->GetProperty("levelwindow")); + + if (levelWindowProperty.IsNotNull()) + { + std::string name; + node->GetName(name); + QString item = name.c_str(); + QAction *id = m_ImageSubmenu->addAction(item); + id->setCheckable(true); + m_Images[id] = levelWindowProperty; + if (levelWindowProperty == m_Manager->GetLevelWindowProperty()) { - std::string name; - node->GetName(name); - QString item = name.c_str(); - QAction *id = m_ImageSubmenu->addAction(item); - id->setCheckable(true); - m_Images[id] = levelWindowProperty; - if (levelWindowProperty == m_Manager->GetLevelWindowProperty()) - { - id->setChecked(true); - } + id->setChecked(true); } } } - connect(m_ImageSubmenu, SIGNAL(triggered(QAction *)), this, SLOT(setImage(QAction *))); - contextMenu->addMenu(m_ImageSubmenu); + connect(m_ImageSubmenu, &QMenu::triggered, this, &QmitkLevelWindowWidgetContextMenu::OnSetImage); + + contextMenu->addMenu(m_ImageSubmenu); contextMenu->exec(QCursor::pos()); } catch (...) { } } -void QmitkLevelWindowWidgetContextMenu::getContextMenu() +void QmitkLevelWindowWidgetContextMenu::GetContextMenu() { auto contextMenu = new QMenu(this); - getContextMenu(contextMenu); + GetContextMenu(contextMenu); delete contextMenu; } diff --git a/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp index be5ad4ac87..6bb58cb3d3 100644 --- a/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkLineEditLevelWindowWidget.cpp @@ -1,182 +1,172 @@ /*=================================================================== 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 "QmitkLineEditLevelWindowWidget.h" -#include "QmitkLevelWindowWidgetContextMenu.h" +// mitk core #include +// mitk qt widgets +#include + +// qt #include #include #include + +// itk #include + +// c++ #include #include -using namespace std; - -/** -* Constructor -*/ QmitkLineEditLevelWindowWidget::QmitkLineEditLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Manager = mitk::LevelWindowManager::New(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkLineEditLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; - m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); // true); + m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); auto layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); m_LevelInput = new QLineEdit(this); m_LevelInput->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); m_LevelInput->setToolTip("Edit this field to change the center of the levelwindow."); - // m_LevelInput->setFrameShape( QLineEdit::LineEditPanel ); - // m_LevelInput->setFrameShadow( QLineEdit::Sunken ); m_WindowInput = new QLineEdit(this); m_WindowInput->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); m_WindowInput->setToolTip( "Edit this field to change the span of the levelwindow. This number describes the whole span around the center."); - // m_WindowInput->setFrameShape( QLineEdit::LineEditPanel ); - // m_WindowInput->setFrameShadow( QLineEdit::Sunken ); layout->addWidget(m_LevelInput); layout->addWidget(m_WindowInput); // signals and slots connections connect(m_LevelInput, SIGNAL(editingFinished()), this, SLOT(SetLevelValue())); connect(m_WindowInput, SIGNAL(editingFinished()), this, SLOT(SetWindowValue())); // Validator for both LineEdit-widgets, to limit the valid input-range to int. - // QValidator* validatorWindowInput = new QIntValidator(1, 20000000, this); - QValidator *validatorWindowInput = new QDoubleValidator(0, numeric_limits::max(), 2, this); + QValidator *validatorWindowInput = new QDoubleValidator(0, std::numeric_limits::max(), 2, this); m_WindowInput->setValidator(validatorWindowInput); - // QValidator* validatorLevelInput = new QIntValidator(-10000000, 10000000, this); - // QValidator* validatorLevelInput = new QDoubleValidator(numeric_limits::min(), - // numeric_limits::max(), 2, this); - // m_LevelInput->setValidator(validatorLevelInput); - this->hide(); } QmitkLineEditLevelWindowWidget::~QmitkLineEditLevelWindowWidget() { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } } void QmitkLineEditLevelWindowWidget::OnPropertyModified(const itk::EventObject &) { try { m_LevelWindow = m_Manager->GetLevelWindow(); - // setValidator(); QString level; QString window; if (m_LevelWindow.IsFloatingValues()) { std::stringstream ssLevel; std::stringstream ssWindow; ssLevel << std::setprecision(3) << m_LevelWindow.GetLevel(); ssWindow << std::setprecision(3) << m_LevelWindow.GetWindow(); level = ssLevel.str().c_str(); window = ssWindow.str().c_str(); } else { level.setNum((int)(m_LevelWindow.GetLevel())); window.setNum((int)(m_LevelWindow.GetWindow())); } m_LevelInput->setText(level); m_WindowInput->setText(window); m_LevelInput->setEnabled(!m_LevelWindow.IsFixed()); m_WindowInput->setEnabled(!m_LevelWindow.IsFixed()); this->show(); } catch (...) { try { this->hide(); } catch (...) { } } } -void QmitkLineEditLevelWindowWidget::setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) +void QmitkLineEditLevelWindowWidget::SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } m_Manager = levelWindowManager; if (m_Manager.IsNotNull()) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkLineEditLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; } } void QmitkLineEditLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } -// read the levelInput and change level and slider when the button "ENTER" was pressed in the windowInput-LineEdit void QmitkLineEditLevelWindowWidget::SetLevelValue() { double level = m_LevelInput->text().toDouble(); m_LevelWindow.SetLevelWindow(level, m_LevelWindow.GetWindow()); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -// read the windowInput and change window and slider when the button "ENTER" was pressed in the windowInput-LineEdit void QmitkLineEditLevelWindowWidget::SetWindowValue() { double window = m_WindowInput->text().toDouble(); m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), window); m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLineEditLevelWindowWidget::contextMenuEvent(QContextMenuEvent *) { - m_Contextmenu->setLevelWindowManager(m_Manager.GetPointer()); - m_Contextmenu->getContextMenu(); + m_Contextmenu->SetLevelWindowManager(m_Manager.GetPointer()); + m_Contextmenu->GetContextMenu(); } mitk::LevelWindowManager *QmitkLineEditLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); -} \ No newline at end of file +} diff --git a/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp b/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp index d491d9185c..1642b8c67b 100644 --- a/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkSliderLevelWindowWidget.cpp @@ -1,570 +1,554 @@ /*=================================================================== 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 +// mitk core +#include + +// mitk qt widgets +#include + +// qt #include #include #include #include -#include +// itk #include -#include +// c++ #include -/** -* Constructor -*/ -QmitkSliderLevelWindowWidget::QmitkSliderLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) +QmitkSliderLevelWindowWidget::QmitkSliderLevelWindowWidget(QWidget *parent, Qt::WindowFlags f) + : QWidget(parent, f) { m_Manager = mitk::LevelWindowManager::New(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; setMouseTracking(true); m_Resize = false; m_Bottom = false; m_CtrlPressed = false; m_MouseDown = false; m_Font.setPointSize(6); m_MoveHeight = height() - 25; m_ScaleVisible = true; - m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); //, true); - - // setBackgroundMode( Qt::NoBackground ); + m_Contextmenu = new QmitkLevelWindowWidgetContextMenu(this); this->hide(); - update(); + Update(); } QmitkSliderLevelWindowWidget::~QmitkSliderLevelWindowWidget() { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } } -void QmitkSliderLevelWindowWidget::setLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) +void QmitkSliderLevelWindowWidget::SetLevelWindowManager(mitk::LevelWindowManager *levelWindowManager) { if (m_IsObserverTagSet) { m_Manager->RemoveObserver(m_ObserverTag); m_IsObserverTagSet = false; } m_Manager = levelWindowManager; if (m_Manager.IsNotNull()) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSliderLevelWindowWidget::OnPropertyModified); m_ObserverTag = m_Manager->AddObserver(itk::ModifiedEvent(), command); m_IsObserverTagSet = true; } } void QmitkSliderLevelWindowWidget::OnPropertyModified(const itk::EventObject &) { try { m_LevelWindow = m_Manager->GetLevelWindow(); this->show(); - update(); + Update(); } catch (...) { try { this->hide(); } catch (...) { } } } void QmitkSliderLevelWindowWidget::paintEvent(QPaintEvent *itkNotUsed(e)) { QPixmap pm(width(), height()); pm.fill(this->palette().color(this->backgroundRole())); QPainter painter(&pm); painter.setFont(m_Font); painter.setPen(this->palette().color(this->foregroundRole())); QColor c(51, 153, 204); QColor cl = c.light(); QColor cd = c.dark(); painter.setBrush(c); painter.drawRect(m_Rect); float mr = m_LevelWindow.GetRange(); float smallestLevelableValue = 1e-9; //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges //from images, but old scene serialization may contain infinite ranges that overwrite the new //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962. //Until LevelWindow and this widget is refactored the check was the minimal invasive fix. if (!std::isfinite(mr)) { mr = m_LevelWindow.GetWindow(); } // avoiding a division by 0 while still enabling small level windows if (mr < smallestLevelableValue) mr = smallestLevelableValue; float fact = (float)m_MoveHeight / mr; // begin draw scale if (m_ScaleVisible) { double minRange = (double)m_LevelWindow.GetRangeMin(); double maxRange = (double)m_LevelWindow.GetRangeMax(); //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges //from images, but old scene serialization may contain infinite ranges that overwrite the new //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962. //Until LevelWindow and this widget is refactored the check was the minimal invasive fix. if (!std::isfinite(minRange)) { minRange = m_LevelWindow.GetLowerWindowBound(); } //This check is needed as safe guard. LevelWindow is refactored to only deduce finite ranges //from images, but old scene serialization may contain infinite ranges that overwrite the new //business logic. This roots in two many "jobs" LevelWindow" is used for; see also T24962. //Until LevelWindow and this widget is refactored the check was the minimal invasive fix. if (!std::isfinite(maxRange)) { maxRange = m_LevelWindow.GetUpperWindowBound(); } int yValue = m_MoveHeight + (int)(minRange * fact); QString s = " 0"; if (minRange < 0 && maxRange > 0) { painter.drawLine(5, yValue, 15, yValue); painter.drawText(21, yValue + 3, s); } int count = 1; int k = 5; bool enoughSpace = false; bool enoughSpace2 = false; double dStepSize = pow(10, floor(log10(mr / 100)) + 1); for (int i = m_MoveHeight + (int)(minRange * fact); i < m_MoveHeight;) // negative { if (-count * dStepSize < minRange) { break; } yValue = m_MoveHeight + (int)((minRange + count * dStepSize) * fact); s = QString::number(-count * dStepSize); if (count % k && ((dStepSize * fact) > 2.5)) { painter.drawLine(8, yValue, 12, yValue); enoughSpace = true; } else if (!(count % k)) { if ((k * dStepSize * fact) > 7) { painter.drawLine(5, yValue, 15, yValue); painter.drawText(21, yValue + 3, s); enoughSpace2 = true; } else { k += 5; } } if (enoughSpace) { i = yValue; count++; } else if (enoughSpace2) { i = yValue; count += k; } else { i = yValue; count = k; } } count = 1; k = 5; enoughSpace = false; enoughSpace2 = false; for (int i = m_MoveHeight + (int)(minRange * fact); i >= 0;) { if (count * dStepSize > maxRange) { break; } yValue = m_MoveHeight + (int)((minRange - count * dStepSize) * fact); s = QString::number(count * dStepSize); if (count % k && ((dStepSize * fact) > 2.5)) { if (!(minRange > 0 && (count * dStepSize) < minRange)) painter.drawLine(8, yValue, 12, yValue); enoughSpace = true; } else if (!(count % k)) { if ((k * dStepSize * fact) > 7) { if (!(minRange > 0 && (count * dStepSize) < minRange)) { painter.drawLine(5, yValue, 15, yValue); painter.drawText(21, yValue + 3, s); } enoughSpace2 = true; } else { k += 5; } } if (enoughSpace) { i = yValue; count++; } else if (enoughSpace2) { i = yValue; count += k; } else { i = yValue; count = k; } } } // end draw scale painter.setPen(cl); painter.drawLine(m_Rect.topLeft(), m_Rect.topRight()); painter.drawLine(m_Rect.topLeft(), m_Rect.bottomLeft()); painter.setPen(cd); painter.drawLine(m_Rect.topRight(), m_Rect.bottomRight()); painter.drawLine(m_Rect.bottomRight(), m_Rect.bottomLeft()); painter.end(); QPainter p(this); p.drawPixmap(0, 0, pm); } -/** -* -*/ void QmitkSliderLevelWindowWidget::mouseMoveEvent(QMouseEvent *mouseEvent) { if (!mouseEvent) return; if (m_LevelWindow.IsFixed()) return; if (!m_MouseDown) { if (mouseEvent->pos().y() >= 0 && mouseEvent->pos().y() <= (m_Rect.topLeft().y() + 3)) { setCursor(Qt::SizeVerCursor); m_UpperBound.setRect(m_Rect.topLeft().x(), m_Rect.topLeft().y() - 3, 17, 7); this->setToolTip("Ctrl + left click to change only upper bound"); m_Resize = true; } else if (mouseEvent->pos().y() >= (m_Rect.bottomLeft().y() - 3)) { setCursor(Qt::SizeVerCursor); m_LowerBound.setRect(m_Rect.bottomLeft().x(), m_Rect.bottomLeft().y() - 3, 17, 7); this->setToolTip("Ctrl + left click to change only lower bound"); m_Resize = true; m_Bottom = true; } else { setCursor(Qt::ArrowCursor); this->setToolTip("Left click and mouse move to adjust the slider"); m_Resize = false; m_Bottom = false; } } else { float fact = (float)m_MoveHeight / m_LevelWindow.GetRange(); if (m_Leftbutton) { if (m_Resize && !m_CtrlPressed) { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; if (m_Bottom) value = m_LevelWindow.GetWindow() + ((2 * diff)); else value = m_LevelWindow.GetWindow() - ((2 * diff)); if (value < 0) value = 0; m_LevelWindow.SetLevelWindow(m_LevelWindow.GetLevel(), value); } else if (m_Resize && m_CtrlPressed) { if (!m_Bottom) { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; value = m_LevelWindow.GetWindow() - ((diff)); if (value < 0) value = 0; float oldWindow; float oldLevel; float newLevel; oldWindow = m_LevelWindow.GetWindow(); oldLevel = m_LevelWindow.GetLevel(); newLevel = oldLevel + (value - oldWindow) / 2; if (!((newLevel + value / 2) > m_LevelWindow.GetRangeMax())) m_LevelWindow.SetLevelWindow(newLevel, value); } else { double diff = (mouseEvent->pos().y()) / fact; diff -= (m_StartPos.y()) / fact; m_StartPos = mouseEvent->pos(); if (diff == 0) return; float value; value = m_LevelWindow.GetWindow() + ((diff)); if (value < 0) value = 0; float oldWindow; float oldLevel; float newLevel; oldWindow = m_LevelWindow.GetWindow(); oldLevel = m_LevelWindow.GetLevel(); newLevel = oldLevel - (value - oldWindow) / 2; if (!((newLevel - value / 2) < m_LevelWindow.GetRangeMin())) m_LevelWindow.SetLevelWindow(newLevel, value); } } else { const float minv = m_LevelWindow.GetRangeMin(); const float level = (m_MoveHeight - mouseEvent->pos().y()) / fact + minv; double diff = (mouseEvent->pos().x()) / fact; diff -= (m_StartPos.x()) / fact; m_StartPos = mouseEvent->pos(); float window; if (m_Bottom) window = m_LevelWindow.GetWindow() + ((2 * diff)); else window = m_LevelWindow.GetWindow() - ((2 * diff)); if (window < 0) window = 0; m_LevelWindow.SetLevelWindow(level, window); } m_Manager->SetLevelWindow(m_LevelWindow); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } + void QmitkSliderLevelWindowWidget::enterEvent(QEvent * /*event*/) { - /* - if(event->type() != QEvent::MouseMove) - return;*/ - - // mouseMoveEvent( static_cast< QMouseEvent* > ( event ) ); QPoint p = QCursor::pos(); p = this->mapFromGlobal(p); QMouseEvent ev(QEvent::MouseMove, p, Qt::NoButton, Qt::NoButton, Qt::NoModifier); this->mouseMoveEvent(&ev); } -/** -* -*/ void QmitkSliderLevelWindowWidget::mousePressEvent(QMouseEvent *mouseEvent) { if (m_LevelWindow.IsFixed()) return; m_MouseDown = true; m_StartPos = mouseEvent->pos(); if (mouseEvent->button() == Qt::LeftButton) { if (mouseEvent->modifiers() == Qt::ControlModifier || mouseEvent->modifiers() == Qt::ShiftModifier) { m_CtrlPressed = true; } else { m_CtrlPressed = false; } m_Leftbutton = true; } else m_Leftbutton = false; mouseMoveEvent(mouseEvent); } -/** -* -*/ void QmitkSliderLevelWindowWidget::resizeEvent(QResizeEvent *event) { m_MoveHeight = event->size().height() - 25; - update(); + Update(); } -/** -* -*/ void QmitkSliderLevelWindowWidget::mouseReleaseEvent(QMouseEvent *) { if (m_LevelWindow.IsFixed()) return; m_MouseDown = false; } -/** -* -*/ -void QmitkSliderLevelWindowWidget::update() +void QmitkSliderLevelWindowWidget::Update() { int rectWidth; if (m_ScaleVisible) { rectWidth = 17; setMinimumSize(QSize(50, 50)); setMaximumSize(QSize(50, 2000)); setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); } else { rectWidth = 26; setMinimumSize(QSize(40, 50)); setMaximumSize(QSize(50, 2000)); setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); } float mr = m_LevelWindow.GetRange(); if (mr < 1e-9) mr = 1e-9; float fact = (float)m_MoveHeight / mr; float rectHeight = m_LevelWindow.GetWindow() * fact; if (rectHeight < 15) rectHeight = 15; if (m_LevelWindow.GetLowerWindowBound() < 0) m_Rect.setRect(2, (int)(m_MoveHeight - (m_LevelWindow.GetUpperWindowBound() - m_LevelWindow.GetRangeMin()) * fact), rectWidth, (int)rectHeight); else m_Rect.setRect(2, (int)(m_MoveHeight - (m_LevelWindow.GetUpperWindowBound() - m_LevelWindow.GetRangeMin()) * fact), rectWidth, (int)rectHeight); QWidget::repaint(); } void QmitkSliderLevelWindowWidget::contextMenuEvent(QContextMenuEvent *) { - m_Contextmenu->setLevelWindowManager(m_Manager.GetPointer()); + m_Contextmenu->SetLevelWindowManager(m_Manager.GetPointer()); auto contextMenu = new QMenu(this); Q_CHECK_PTR(contextMenu); if (m_ScaleVisible) - contextMenu->addAction(tr("Hide Scale"), this, SLOT(hideScale())); + contextMenu->addAction(tr("Hide Scale"), this, SLOT(HideScale())); else - contextMenu->addAction(tr("Show Scale"), this, SLOT(showScale())); + contextMenu->addAction(tr("Show Scale"), this, SLOT(ShowScale())); contextMenu->addSeparator(); - m_Contextmenu->getContextMenu(contextMenu); + m_Contextmenu->GetContextMenu(contextMenu); // Fix: Bug #13327 we need to reset the m_MouseDown value // otherwise the cursor is not correctly restored afterwards m_MouseDown = false; } -void QmitkSliderLevelWindowWidget::hideScale() +void QmitkSliderLevelWindowWidget::HideScale() { m_ScaleVisible = false; - update(); + Update(); } -void QmitkSliderLevelWindowWidget::showScale() +void QmitkSliderLevelWindowWidget::ShowScale() { m_ScaleVisible = true; - update(); + Update(); } -void QmitkSliderLevelWindowWidget::setDataStorage(mitk::DataStorage *ds) +void QmitkSliderLevelWindowWidget::SetDataStorage(mitk::DataStorage *ds) { m_Manager->SetDataStorage(ds); } mitk::LevelWindowManager *QmitkSliderLevelWindowWidget::GetManager() { return m_Manager.GetPointer(); }