diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake index b8e9e5988b..7b481c1ce2 100644 --- a/Modules/Core/files.cmake +++ b/Modules/Core/files.cmake @@ -1,315 +1,320 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCoreActivator.cpp mitkCoreObjectFactoryBase.cpp mitkCoreObjectFactory.cpp mitkCoreServices.cpp mitkException.cpp Algorithms/mitkBaseDataSource.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkCompareImageDataFilter.cpp Algorithms/mitkCompositePixelValueToString.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkExtractSliceFilter2.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAnatomicalStructureColorPresets.cpp DataManagement/mitkArbitraryTimeGeometry.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkApplyTransformMatrixOperation.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseGeometry.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataStorage.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkFloatPropertyExtension.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGeometryTransformHolder.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkGenericIDRelationRule.cpp DataManagement/mitkIdentifiable.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageReadAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageVtkReadAccessor.cpp DataManagement/mitkImageVtkWriteAccessor.cpp DataManagement/mitkImageWriteAccessor.cpp DataManagement/mitkIntPropertyExtension.cpp DataManagement/mitkIPersistenceService.cpp DataManagement/mitkIPropertyAliases.cpp DataManagement/mitkIPropertyDescriptions.cpp DataManagement/mitkIPropertyExtensions.cpp DataManagement/mitkIPropertyFilters.cpp DataManagement/mitkIPropertyOwner.cpp DataManagement/mitkIPropertyPersistence.cpp DataManagement/mitkIPropertyProvider.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLine.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTableProperty.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMaterial.cpp DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModifiedLock.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDataUID.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateFunction.cpp DataManagement/mitkNodePredicateGeometry.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateDataProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkNumericConstants.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneGeometryData.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkPointSetShapeProperty.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyAliases.cpp DataManagement/mitkPropertyDescriptions.cpp DataManagement/mitkPropertyExtension.cpp DataManagement/mitkPropertyExtensions.cpp DataManagement/mitkPropertyFilter.cpp DataManagement/mitkPropertyFilters.cpp DataManagement/mitkPropertyKeyPath.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkPropertyListReplacedObserver.cpp DataManagement/mitkPropertyNameHelper.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkPropertyPersistence.cpp DataManagement/mitkPropertyPersistenceInfo.cpp DataManagement/mitkPropertyRelationRuleBase.cpp DataManagement/mitkProportionalTimeGeometry.cpp DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkScaleOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTemporoSpatialStringProperty.cpp DataManagement/mitkUIDManipulator.cpp DataManagement/mitkVector.cpp DataManagement/mitkVectorProperty.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkIPropertyRelations.cpp DataManagement/mitkPropertyRelations.cpp Interactions/mitkAction.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCrosshairPositionEvent.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp + Interactions/mitkDisplayActionEventBroadcast.cpp + Interactions/mitkDisplayActionEventFunctions.cpp + Interactions/mitkDisplayActionEventHandler.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventFactory.cpp Interactions/mitkEventRecorder.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkInteractionEventConst.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkInteractionEventObserver.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkInteractionPositionEvent.cpp + Interactions/mitkInteractionSchemeSwitcher.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkMouseDoubleClickEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkSinglePointDataInteractor.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineCondition.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp + Interactions/mitkStdDisplayActionEventHandler.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkXML2EventParser.cpp IO/mitkAbstractFileIO.cpp IO/mitkAbstractFileReader.cpp IO/mitkAbstractFileWriter.cpp IO/mitkCustomMimeType.cpp IO/mitkFileReader.cpp IO/mitkFileReaderRegistry.cpp IO/mitkFileReaderSelector.cpp IO/mitkFileReaderWriterBase.cpp IO/mitkFileWriter.cpp IO/mitkFileWriterRegistry.cpp IO/mitkFileWriterSelector.cpp IO/mitkGeometry3DToXML.cpp IO/mitkIFileIO.cpp IO/mitkIFileReader.cpp IO/mitkIFileWriter.cpp IO/mitkGeometryDataReaderService.cpp IO/mitkGeometryDataWriterService.cpp IO/mitkImageGenerator.cpp IO/mitkImageVtkLegacyIO.cpp IO/mitkImageVtkXmlIO.cpp IO/mitkIMimeTypeProvider.cpp IO/mitkIOConstants.cpp IO/mitkIOMimeTypes.cpp IO/mitkIOUtil.cpp IO/mitkItkImageIO.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkLegacyFileReaderService.cpp IO/mitkLegacyFileWriterService.cpp IO/mitkLocaleSwitch.cpp IO/mitkLog.cpp IO/mitkMimeType.cpp IO/mitkMimeTypeProvider.cpp IO/mitkOperation.cpp IO/mitkPixelType.cpp IO/mitkPointSetReaderService.cpp IO/mitkPointSetWriterService.cpp IO/mitkProportionalTimeGeometryToXML.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSurfaceStlIO.cpp IO/mitkSurfaceVtkIO.cpp IO/mitkSurfaceVtkLegacyIO.cpp IO/mitkSurfaceVtkXmlIO.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkPreferenceListReaderOptionsFunctor.cpp Rendering/mitkAbstractAnnotationRenderer.cpp Rendering/mitkAnnotationUtils.cpp Rendering/mitkBaseRenderer.cpp #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module Rendering/mitkGradientBackground.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/mitkMapper.cpp Rendering/mitkAnnotation.cpp Rendering/mitkPlaneGeometryDataMapper2D.cpp Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp Rendering/mitkPointSetVtkMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowFrame.cpp #Rendering/mitkSurfaceGLMapper2D.cpp Moved to deprecated LegacyGL Module Rendering/mitkSurfaceVtkMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp ) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/DisplayConfigMITKNoCrosshair.xml Interactions/DisplayConfigMITKRotation.xml Interactions/DisplayConfigMITKRotationUnCoupled.xml Interactions/DisplayConfigMITKSwivel.xml Interactions/DisplayConfigMITKLimited.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml mitkLevelWindowPresets.xml mitkAnatomicalStructureColorPresets.xml ) diff --git a/Modules/Core/include/mitkDataStorage.h b/Modules/Core/include/mitkDataStorage.h index 80eaf630c2..b382752c63 100644 --- a/Modules/Core/include/mitkDataStorage.h +++ b/Modules/Core/include/mitkDataStorage.h @@ -1,448 +1,451 @@ /*=================================================================== 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 MITKDATASTORAGE_H #define MITKDATASTORAGE_H #include "itkObject.h" #include "itkSimpleFastMutexLock.h" #include "itkVectorContainer.h" #include "mitkDataNode.h" #include "mitkGeometry3D.h" #include "mitkMessage.h" #include #include namespace mitk { class NodePredicateBase; class DataNode; class BaseRenderer; //##Documentation //## @brief Data management class that handles 'was created by' relations //## //## The DataStorage provides data storage and management functionality. //## It handles a 'was created by' relation by associating each data object with a //## set of source objects, that this object was created from. //## Thus, nodes are stored in a noncyclical directed graph data structure. //## If a new node is added to the DataStorage, AddNodeEvent is emitted. //## If a node is removed, RemoveNodeEvent is emitted. //## //## //## \ingroup DataStorage class MITKCORE_EXPORT DataStorage : public itk::Object { public: mitkClassMacroItkParent(DataStorage, itk::Object); //##Documentation //## @brief A Container of objects that is used as a result set of GetSubset() query operations (Set of //SmartPointers // to DataNodes). typedef itk::VectorContainer SetOfObjects; //##Documentation //## @brief Adds a DataNode containing a data object to its internal storage //## //## This Method adds a new data object to the DataStorage. The new object is //## passed in the first parameter. The second parameter is a set //## of source objects, that were used to create this object. The new object will have //## a 'was created from' relation to its source objects. //## the addition of a new object will fire the notification mechanism. //## If the node parameter is nullptr or if the DataNode has already been added, //## an exception will be thrown. virtual void Add(DataNode *node, const DataStorage::SetOfObjects *parents = nullptr) = 0; //##Documentation //## @brief Convenience method to add a node that has one parent //## void Add(DataNode *node, DataNode *parent); //##Documentation //## @brief Removes node from the DataStorage //## virtual void Remove(const DataNode *node) = 0; //##Documentation //## @brief Checks if a node exists in the DataStorage //## virtual bool Exists(const DataNode *node) const = 0; //##Documentation //## @brief Removes a set of nodes from the DataStorage //## void Remove(const DataStorage::SetOfObjects *nodes); //##Documentation //## @brief returns a set of data objects that meet the given condition(s) //## //## GetSubset returns a set of objects with a specific data type that meet the condition(s) //## specified in the condition parameter. Conditions can be //## - data type of the data object //## - is source object of specific object (e.g. all source objects of node x) //## - has property with specific value (e.g. OrganType is Liver) //## - negation of any condition //## - conjunction of a set of conditions //## - disjunction of a set of conditions //## Conditions are implemented as predicates using the Composite Design Pattern //## (see definition of NodePredicateBase for details). //## The method returns a set of SmartPointers to the DataNodes that fulfill the //## conditions. A set of all objects can be retrieved with the GetAll() method; SetOfObjects::ConstPointer GetSubset(const NodePredicateBase *condition) const; //##Documentation //## @brief returns a set of source objects for a given node that meet the given condition(s). //## virtual SetOfObjects::ConstPointer GetSources(const DataNode *node, const NodePredicateBase *condition = nullptr, bool onlyDirectSources = true) const = 0; //##Documentation //## @brief returns a set of derived objects for a given node. //## //## GetDerivations() returns a set of objects that are derived from the DataNode node. //## This means, that node was used to create the returned objects. If the parameter //## onlyDirectDerivations is set to true (default value), only objects that directly have //## node as one of their source objects will be returned. Otherwise, objects that are //## derived from derivations of node are returned too. //## The derived objects can be filtered with a predicate object as described in the GetSubset() //## method by providing a predicate as the condition parameter. virtual SetOfObjects::ConstPointer GetDerivations(const DataNode *node, const NodePredicateBase *condition = nullptr, bool onlyDirectDerivations = true) const = 0; //##Documentation //## @brief returns a set of all data objects that are stored in the data storage //## virtual SetOfObjects::ConstPointer GetAll() const = 0; //##Documentation //## @brief Convenience method to get the first node that matches the predicate condition //## DataNode *GetNode(const NodePredicateBase *condition = nullptr) const; //##Documentation //## @brief Convenience method to get the first node with a given name //## DataNode *GetNamedNode(const char *name) const; //##Documentation //## @brief Convenience method to get the first node with a given name //## DataNode *GetNamedNode(const std::string name) const { return this->GetNamedNode(name.c_str()); } //##Documentation //## @brief Convenience method to get the first node with a given name that is derived from sourceNode //## DataNode *GetNamedDerivedNode(const char *name, const DataNode *sourceNode, bool onlyDirectDerivations = true) const; //##Documentation //## @brief Convenience method to get the first data object of a given data type with a given name //## template DataType *GetNamedObject(const char *name) const { if (name == nullptr) return nullptr; DataNode *n = this->GetNamedNode(name); if (n == nullptr) return nullptr; else return dynamic_cast(n->GetData()); } //##Documentation //## @brief Convenience method to get the first data object of a given data type with a given name //## template DataType *GetNamedObject(const std::string name) const { return this->GetNamedObject(name.c_str()); } //##Documentation //## @brief Convenience method to get the first data object of a given data type with a given name that is derived // from a specific node //## template DataType *GetNamedDerivedObject(const char *name, const DataNode *sourceNode, bool onlyDirectDerivations = true) const { if (name == nullptr) return nullptr; DataNode *n = this->GetNamedDerivedNode(name, sourceNode, onlyDirectDerivations); if (n == nullptr) return nullptr; else return dynamic_cast(n->GetData()); } //##Documentation //## @brief Returns a list of used grouptags //## const DataNode::GroupTagList GetGroupTags() const; /*ITK Mutex */ mutable itk::SimpleFastMutexLock m_MutexOne; /* Public Events */ typedef Message1 DataStorageEvent; //##Documentation //## @brief AddEvent is emitted whenever a new node has been added to the DataStorage. //## //## Observers should register to this event by calling myDataStorage->AddNodeEvent.AddListener(myObject, // MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called every time a new node has been added to the DataStorage. //## Observers should unregister by calling myDataStorage->AddNodeEvent.RemoveListener(myObject, //MyObject::MyMethod). //## Note: AddEvents are _not_ emitted if a node is added to DataStorage by adding it to the the underlying //DataTree! // member variable is not needed to be locked in multi threaded scenarios since the DataStorageEvent is a typedef // for // a Message1 object which is thread safe DataStorageEvent AddNodeEvent; //##Documentation //## @brief RemoveEvent is emitted directly before a node is removed from the DataStorage. //## //## Observers should register to this event by calling myDataStorage->RemoveNodeEvent.AddListener(myObject, // MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called every time a new node has been added to the DataStorage. //## Observers should unregister by calling myDataStorage->RemoveNodeEvent.RemoveListener(myObject, // MyObject::MyMethod). //## Note: RemoveEvents are also emitted if a node was removed from the DataStorage by deleting it from the //underlying // DataTree // member variable is not needed to be locked in multi threaded scenarios since the DataStorageEvent is a typedef // for // a Message1 object which is thread safe DataStorageEvent RemoveNodeEvent; //##Documentation //## @brief ChangedEvent is emitted directly after a node was changed. //## //## Observers should register to this event by calling myDataStorage->ChangedNodeEvent.AddListener(myObject, // MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called every time a new node has been changed. //## Observers should unregister by calling myDataStorage->ChangedNodeEvent.RemoveListener(myObject, // MyObject::MyMethod). //## Internally the DataStorage listens to itk::ModifiedEvents on the nodes and forwards them //## to the listeners of this event. // member variable is not needed to be locked in multi threaded scenarios since the DataStorageEvent is a typedef // for // a Message1 object which is thread safe DataStorageEvent ChangedNodeEvent; //##Documentation //## @brief DeleteNodeEvent is emitted directly before a node is deleted. //## //## Observers should register to this event by calling myDataStorage->DeleteNodeEvent.AddListener(myObject, // MyObject::MyMethod). //## After registering, myObject->MyMethod() will be called when a node is deleted. //## Observers should unregister by calling myDataStorage->DeleteNodeEvent.RemoveListener(myObject, // MyObject::MyMethod). //## Internally the DataStorage listens to itk::DeleteEvents on the nodes and forwards them //## to the listeners of this event. // member variable is not needed to be locked in multi threaded scenarios since the DataStorageEvent is a typedef // for // a Message1 object which is thread safe DataStorageEvent DeleteNodeEvent; DataStorageEvent InteractorChangedNodeEvent; //##Documentation //## @brief Compute the axis-parallel bounding geometry of the input objects //## //## Throws std::invalid_argument exception if input is nullptr //## @param input set of objects of the DataStorage to be included in the bounding geometry //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey TimeGeometry::ConstPointer ComputeBoundingGeometry3D(const SetOfObjects *input, const char *boolPropertyKey = nullptr, const BaseRenderer *renderer = nullptr, const char *boolPropertyKey2 = nullptr) const; //##Documentation //## @brief Compute the axis-parallel bounding geometry of the data tree //## (bounding box, minimal spacing of the considered nodes, live-span) //## //## it -> an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey TimeGeometry::ConstPointer ComputeBoundingGeometry3D(const char *boolPropertyKey = nullptr, const BaseRenderer *renderer = nullptr, const char *boolPropertyKey2 = nullptr) const; //##Documentation //## @brief Compute the axis-parallel bounding geometry of all visible parts of the //## data tree bounding box, minimal spacing of the considered nodes, live-span) //## //## Simply calls ComputeBoundingGeometry3D(it, "visible", renderer, boolPropertyKey). //## it -> an iterator of a data tree structure //## @param renderer the reference to the renderer //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. TimeGeometry::ConstPointer ComputeVisibleBoundingGeometry3D(const BaseRenderer *renderer = nullptr, const char *boolPropertyKey = nullptr); //##Documentation //## @brief Compute the bounding box of data tree structure //## it -> an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey BoundingBox::Pointer ComputeBoundingBox(const char *boolPropertyKey = nullptr, const BaseRenderer *renderer = nullptr, const char *boolPropertyKey2 = nullptr); //##Documentation //## \brief Compute the bounding box of all visible parts of the data tree structure, for general //## rendering or renderer specific visibility property checking //## //## Simply calls ComputeBoundingBox(it, "visible", renderer, boolPropertyKey). //## it -> an iterator of a data tree structure //## @param renderer the reference to the renderer //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the bounding-box calculation. BoundingBox::Pointer ComputeVisibleBoundingBox(const BaseRenderer *renderer = nullptr, const char *boolPropertyKey = nullptr) { return ComputeBoundingBox("visible", renderer, boolPropertyKey); } //##Documentation //## @brief Compute the time-bounds of the contents of a data tree structure //## //## The methods returns only [-infinity, +infinity], if all data-objects have an infinite live-span. Otherwise, //## all data-objects with infinite live-span are ignored. //## it -> an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the time-bounds calculation. //## @param renderer see @a boolPropertyKey //## @param boolPropertyKey2 a second condition that is applied additionally to @a boolPropertyKey TimeBounds ComputeTimeBounds(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2); //##Documentation //## @brief Compute the time-bounds of all visible parts of the data tree structure, for general //## rendering or renderer specific visibility property checking //## //## The methods returns only [-infinity, +infinity], if all data-objects have an infinite live-span. Otherwise, //## all data-objects with infinite live-span are ignored. //## Simply calls ComputeTimeBounds(it, "visible", renderer, boolPropertyKey). //## @param it an iterator to a data tree structure //## @param boolPropertyKey if a BoolProperty with this boolPropertyKey exists for a node (for @a renderer) //## and is set to @a false, the node is ignored for the time-bounds calculation. //## @param renderer see @a boolPropertyKey TimeBounds ComputeTimeBounds(const BaseRenderer *renderer, const char *boolPropertyKey) { return ComputeTimeBounds("visible", renderer, boolPropertyKey); } //##Documentation //## @brief Defines whether or not NodeChangedEvent is invoked . //## //## This method can be used to set m_BlockNodeModifiedEvents. //## //## If this flag is true, NodeChangedEvent is not invoked when a //## DataNode is modified. This might be undesired when setting //## many properties on a datanode and you do not want anyone to //## react. void BlockNodeModifiedEvents(bool block); protected: //##Documentation //## @brief EmitAddNodeEvent emits the AddNodeEvent //## //## This method should be called by subclasses to emit the AddNodeEvent void EmitAddNodeEvent(const DataNode *node); //##Documentation //## @brief EmitRemoveNodeEvent emits the RemoveNodeEvent //## //## This method should be called by subclasses to emit the RemoveNodeEvent void EmitRemoveNodeEvent(const DataNode *node); void OnNodeInteractorChanged(itk::Object *caller, const itk::EventObject &event); //##Documentation //## @brief OnNodeModified listens to modified events of DataNodes. //## //## The node is hidden behind the caller parameter, which has to be casted first. //## If the cast succeeds the ChangedNodeEvent is emitted with this node. void OnNodeModifiedOrDeleted(const itk::Object *caller, const itk::EventObject &event); //##Documentation //## @brief Adds a Modified-Listener to the given Node. void AddListeners(const DataNode *_Node); //##Documentation //## @brief Removes a Modified-Listener from the given Node. void RemoveListeners(const DataNode *_Node); //##Documentation //## @brief Saves Modified-Observer Tags for each node in order to remove the event listeners again. std::map m_NodeModifiedObserverTags; std::map m_NodeInteractorChangedObserverTags; //##Documentation //## @brief Saves Delete-Observer Tags for each node in order to remove the event listeners again. std::map m_NodeDeleteObserverTags; //##Documentation //## @brief If this class changes nodes itself, set this to TRUE in order //## to suppress NodeChangedEvent to be emitted. bool m_BlockNodeModifiedEvents; //##Documentation //## @brief Standard Constructor for ::New() instantiation DataStorage(); //##Documentation //## @brief Standard Destructor ~DataStorage() override; //##Documentation //## @brief Filters a SetOfObjects by the condition. If no condition is provided, the original set is returned SetOfObjects::ConstPointer FilterSetOfObjects(const SetOfObjects *set, const NodePredicateBase *condition) const; //##Documentation //## @brief Prints the contents of the DataStorage to os. Do not call directly, call ->Print() instead void PrintSelf(std::ostream &os, itk::Indent indent) const override; }; //##Documentation //## @brief returns the topmost visible node of a given list of nodes. + //## The function returns a node that is visible and has the highest layer of a set of given nodes. + //## The property list, which is used to find the visibility- and layer-property is is specified by the + //## given base renderer. //## - MITKCORE_EXPORT DataNode::Pointer FindTopmostVisibleNode(const DataStorage::SetOfObjects* nodes, - const Point3D worldposition, + MITKCORE_EXPORT DataNode::Pointer FindTopmostVisibleNode(const DataStorage::SetOfObjects::ConstPointer nodes, + const Point3D worldPosition, const TimePointType timePoint, const BaseRenderer* baseRender); } // namespace mitk #endif // MITKDATASTORAGE_H diff --git a/Modules/Core/include/mitkDisplayActionEventBroadcast.h b/Modules/Core/include/mitkDisplayActionEventBroadcast.h new file mode 100644 index 0000000000..ec3e59ba11 --- /dev/null +++ b/Modules/Core/include/mitkDisplayActionEventBroadcast.h @@ -0,0 +1,224 @@ +/*=================================================================== + + The Medical Imaging Interaction Toolkit (MITK) + + Copyright (c) German Cancer Research Center, + Division of Medical Image Computing. + All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. + + See LICENSE.txt or http://www.mitk.org for details. + + ===================================================================*/ + +#ifndef MITKDISPLAYACTIONEVENTBROADCAST_H +#define MITKDISPLAYACTIONEVENTBROADCAST_H + +#include "mitkInteractionEventObserver.h" +#include + +namespace mitk +{ + /** + * @brief This class serves as an event state machine while simultaneously observing interaction events. + * It connects the actions from the event state machine .xml-file with concrete functions of this class. + * + * The observed interaction events are mouse events that trigger certain actions, according to an event configuration (e.g. PACS mode). + * These actions are defined and connected inside this broadcast class. + * They typically contain some preprocessing steps and use the results of the preprocessing to broadcast a specific display event. + * + * Any instance that wants to react on the invoked events can call 'AddObserver' on a specific broadcast instance, + * given an itkEventObject and an itkCommand. + */ + class MITKCORE_EXPORT DisplayActionEventBroadcast : public EventStateMachine, public InteractionEventObserver + { + public: + mitkClassMacro(DisplayActionEventBroadcast, EventStateMachine) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** + * By this function this observer is notified about about every 'InteractionEvent'. + * The interaction event is passed to the state machine in order to use its infrastructure. + * For more information see @see InteractionEventObserver. + * + * @par interactionEvent The event that was observed and triggered this notification. + * @par isHandled Flag that indicates if a 'DataInteractor' has already handled the event. + */ + virtual void Notify(InteractionEvent* interactionEvent, bool isHandled) override; + + protected: + + DisplayActionEventBroadcast(); + virtual ~DisplayActionEventBroadcast() override; + + /** + * @brief Connects the action names used in the state machine pattern with functions implemented within this InteractionEventObserver. + */ + void ConnectActionsAndFunctions() override; + /** + * @brief This function is executed when a config object is set / changed (via 'SetEventConfig' or 'AddEventConfig' in 'InteractionEventObserver'). + * It is used to read out the parameters set in the configuration file and to set the member variables accordingly. + */ + virtual void ConfigurationChanged() override; + /** + * @brief Filters the event resp. the sender of the event. + * + * @par interactionEvent The event whose sender has to be checked + * @par data node The data node is ignored in this specific implementation. + * + * @return True, if the sender of the event is a valid sender and the sending renderer is a 2D-renderer. False, if not. + */ + virtual bool FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode) override; + + ////////////////////////////////////////////////////////////////////////// + // Functions to react to interaction events (actions) + ////////////////////////////////////////////////////////////////////////// + /** + * @brief Check if the given interaction event is actually an 'InteractionPositionEvent'. + * + * @par interactionEvent The interaction event that is checked. + * + * @return True, if the given event can be dynamically cast to an 'InteractionPositionEvent'. False, if not. + */ + bool CheckPositionEvent(const InteractionEvent* interactionEvent); + + bool CheckRotationPossible(const InteractionEvent* interactionEvent); + + bool CheckSwivelPossible(const InteractionEvent* interactionEvent); + + void Init(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void Move(StateMachineAction* stateMachineAction , InteractionEvent* interactionEvent); + + void SetCrosshair(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void Zoom(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void Scroll(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void ScrollOneUp(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void ScrollOneDown(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void AdjustLevelWindow(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void StartRotation(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void EndRotation(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void Rotate(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + void Swivel(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + private: + + void UpdateStatusbar(StateMachineAction* stateMachineAction, InteractionEvent* interactionEvent); + + bool GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue); + + /** + * @brief Reference to the service registration of the observer. + * This is needed to unregister the observer on unload. + */ + us::ServiceRegistration m_ServiceRegistration; + + /** + * @brief Determines if this broadcast class reacts to events that already have been processed by a DataInteractor. + * The default value is false. + */ + bool m_AlwaysReact; + + /** + * @brief Coordinate of the mouse pointer at beginning of an interaction (translated to mm unit). + */ + Point2D m_StartCoordinateInMM; + /** + * @brief Coordinate of the mouse pointer in the last step within an interaction. + */ + Point2D m_LastDisplayCoordinate; + /** + * @brief Coordinate of the mouse pointer in the last step within an interaction (translated to mm unit). + */ + Point2D m_LastCoordinateInMM; + /** + * \brief Current coordinates of the pointer. + */ + Point2D m_CurrentDisplayCoordinate; + + /** + * @brief Defines the behavior at the end of a data set. + * If set to true, it will restart at end of data set from the beginning. + */ + bool m_AutoRepeat; + /** + * @brief Defines how many slices are scrolled per pixel that the mouse pointer was moved. + * By default the modifier is 4. This means that when the user moves the cursor by 4 pixels in Y-direction, + * the scene is scrolled by one slice. If the user has moved the the cursor by 20 pixels, the scene is + * scrolled by 5 slices. + * + * If the cursor has moved less than m_IndexToSliceModifier pixels, the scene is scrolled by one slice. + */ + int m_IndexToSliceModifier; + /** + * @brief Defines the scroll behavior. + * Default is up/down movement of pointer performs scrolling + */ + std::string m_ScrollDirection; + /** + * @brief Defines how the axis of interaction influences scroll behavior. + */ + bool m_InvertScrollDirection; + /** + * @brief Defines the zoom behavior. + * Default is up/down movement of pointer performs zooming + */ + std::string m_ZoomDirection; + /** + * @brief Defines how the axis of interaction influences zoom behavior. + */ + bool m_InvertZoomDirection; + /** + * @brief Factor to adjust zooming speed. + */ + float m_ZoomFactor; + /** + * @brief Defines how the axis of interaction influences move behavior. + */ + bool m_InvertMoveDirection; + /** + * @brief Defines the level-window behavior. + * Default is left/right movement of pointer modifies the level. + */ + std::string m_LevelDirection; + /** + * @brief Defines how the axis of interaction influences level-window behavior. + */ + bool m_InvertLevelWindowDirection; + /** + * @brief Determines if the angle between crosshair remains fixed when rotating. + */ + bool m_LinkPlanes; + + typedef std::vector SNCVector; + SNCVector m_RotatableSNCs; + SNCVector m_SNCsToBeRotated; + + Point3D m_LastCursorPosition; + Point3D m_CenterOfRotation; + + Point2D m_ReferenceCursor; + + Vector3D m_RotationPlaneNormal; + Vector3D m_RotationPlaneXVector; + Vector3D m_RotationPlaneYVector; + + Vector3D m_PreviousRotationAxis; + ScalarType m_PreviousRotationAngle; + }; +} // end namespace + +#endif // MITKDISPLAYACTIONEVENTBROADCAST_H diff --git a/Modules/Core/include/mitkDisplayActionEventFunctions.h b/Modules/Core/include/mitkDisplayActionEventFunctions.h new file mode 100644 index 0000000000..519d022c6e --- /dev/null +++ b/Modules/Core/include/mitkDisplayActionEventFunctions.h @@ -0,0 +1,90 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKDISPLAYACTIONEVENTFUNCTIONS_H +#define MITKDISPLAYACTIONEVENTFUNCTIONS_H + +#include + +#include "mitkStdFunctionCommand.h" + +namespace mitk +{ + namespace DisplayActionEventFunctions + { + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplayMoveEvent'. + * The function performs a move of the camera controller of the sending renderer by a vector + * that was previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction MoveSenderCameraAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplaySetCrosshairEvent'. + * The function performs a slice selection of the slice navigation controller and will set + * the cross hair for all 2D-render windows. + * The new position was previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction SetCrosshairAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplayZoomEvent'. + * The function performs a zoom of the camera controller of the sending renderer by a zoom factor + * that was previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ZoomSenderCameraAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplayScrollEvent'. + * The function performs a slice scrolling of the slice navigation controller of the sending renderer. + * The new position was previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ScrollSliceStepperAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplaySetLevelWindowEvent'. + * The function sets the 'levelwindow' property of the topmost visible image that is display by the sending renderer. + * The level and window value for this property were previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction SetLevelWindowAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplayMoveEvent'. + * The function performs a move of the camera controller of all renderer (synchronized) + * by a vector that was previously determined by the mouse interaction event. + * The renderer need to be managed by the same rendering manager. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction MoveCameraSynchronizedAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplaySetCrosshairEvent'. + * The function performs a slice selection of the slice navigation controller and will set + * the cross hair for all 2D-render windows. + * The new position was previously determined by the mouse interaction event. + * #TODO: currently there is no need to distinguish between this and the non-synchronized version + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction SetCrosshairSynchronizedAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplayZoomEvent'. + * The function performs a zoom of the camera controller of all 2D-renderer (synchronized) + * by a zoom factor that was previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ZoomCameraSynchronizedAction(); + /** + * @brief Returns an 'std::function' that can be used to react on the 'DisplayScrollEvent'. + * The function performs a slice scrolling of the slice navigation controller of all 2D-renderer (synchronized). + * The new position was previously determined by the mouse interaction event. + */ + MITKCORE_EXPORT StdFunctionCommand::ActionFunction ScrollSliceStepperSynchronizedAction(); + + } // end namespace DisplayActionEventFunctions +} // end namespace mitk + +#endif // MITKDISPLAYACTIONEVENTFUNCTIONS_H diff --git a/Modules/Core/include/mitkDisplayActionEventHandler.h b/Modules/Core/include/mitkDisplayActionEventHandler.h new file mode 100644 index 0000000000..a45d6acf85 --- /dev/null +++ b/Modules/Core/include/mitkDisplayActionEventHandler.h @@ -0,0 +1,99 @@ +/*=================================================================== + +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 MITKDISPLAYACTIONEVENTHANDLER_H +#define MITKDISPLAYACTIONEVENTHANDLER_H + +#include + +// mitk core +#include "mitkDisplayActionEventBroadcast.h" +#include "mitkDisplayActionEvents.h" +#include "mitkStdFunctionCommand.h" + +namespace mitk +{ + /** + * @brief This class simplifies the process of adding an itkEventObject-itkCommand pair as an observer of a + * DisplayActionEventBroadcast instance. + * The 'SetObservableBroadcast'-function can be used to define the broadcast instance that should be observed. + * The 'ConnectDisplayActionEvent'-function can be used to add a an observer to the broadcast. + * Such an observer consists of a DisplayActionEvent (an itkEventObject) and a StdFunctionCommand (an itkCommand). + * The StdFunctionCommand is created inside the function by the given two std::functions. + */ + class MITKCORE_EXPORT DisplayActionEventHandler + { + 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. + * Attention: All registered commands are removed from the list of observer. + * + * @par observableBroadcast The 'DisplayActionEventBroadcast'-class that should be observed. + */ + void SetObservableBroadcast(DisplayActionEventBroadcast* observableBroadcast); + + /** + * @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 A tag to identify, receive or remove the newly created 'StdFunctionCommand'. + */ + OberserverTagType ConnectDisplayActionEvent(const DisplayActionEvent& displayActionEvent, + const StdFunctionCommand::ActionFunction& actionFunction, + const StdFunctionCommand::FilterFunction& filterFunction = [](const itk::EventObject&) { return true; }); + + /** + * @brief Uses the given observer tag to remove the corresponding custom command 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 tag to identify the 'StdFunctionCommand' observer. + */ + void DisconnectObserver(OberserverTagType observerTag); + + const std::vector& GetAllObserverTags() { return m_ObserverTags; }; + + protected: + + WeakPointer m_ObservableBroadcast; + std::vector m_ObserverTags; + + }; + +} // end namespace mitk + +#endif // MITKDISPLAYACTIONEVENTHANDLER_H diff --git a/Modules/Core/include/mitkDisplayActionEvents.h b/Modules/Core/include/mitkDisplayActionEvents.h new file mode 100644 index 0000000000..22c61e1248 --- /dev/null +++ b/Modules/Core/include/mitkDisplayActionEvents.h @@ -0,0 +1,188 @@ +/*=================================================================== + +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 MITKDISPLAYACTIONEVENTS_H +#define MITKDISPLAYACTIONEVENTS_H + +#include + +// mitk core +#include "mitkInteractionEvent.h" + +// itk +#include + +#include +#include + +namespace mitk +{ + class MITKCORE_EXPORT DisplayActionEvent : public itk::AnyEvent + { + public: + typedef DisplayActionEvent Self; + typedef itk::AnyEvent Superclass; + + DisplayActionEvent() : m_InteractionEvent(nullptr) {} + DisplayActionEvent(InteractionEvent* interactionEvent) : m_InteractionEvent(interactionEvent) {} + virtual ~DisplayActionEvent() {} + virtual const char* GetEventName() const override { return "DisplayActionEvent"; } + virtual bool CheckEvent(const itk::EventObject* e) const override + { return dynamic_cast(e) != nullptr; } + virtual itk::EventObject* MakeObject() const override { return new Self(m_InteractionEvent); } + InteractionEvent* GetInteractionEvent() const { return m_InteractionEvent; } + BaseRenderer* GetSender() const + { + return m_InteractionEvent != nullptr ? m_InteractionEvent->GetSender() : nullptr; + } + DisplayActionEvent(const Self& s) : Superclass(s), m_InteractionEvent(s.GetInteractionEvent()) {}; + + private: + InteractionEvent* m_InteractionEvent; + void operator=(const Self &); + }; + + class MITKCORE_EXPORT DisplayMoveEvent : public DisplayActionEvent + { + public: + typedef DisplayMoveEvent Self; + typedef DisplayActionEvent Superclass; + + DisplayMoveEvent() : Superclass() {} + DisplayMoveEvent(InteractionEvent* interactionEvent, const Vector2D& moveVector) + : Superclass(interactionEvent) + , m_MoveVector(moveVector) + { + } + virtual ~DisplayMoveEvent() {} + virtual const char* GetEventName() const override { return "DisplayMoveEvent"; } + virtual bool CheckEvent(const itk::EventObject* e) const override + { return dynamic_cast(e) != nullptr; } + virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_MoveVector); } + const Vector2D& GetMoveVector() const { return m_MoveVector; } + DisplayMoveEvent(const Self& s) : Superclass(s), m_MoveVector(s.GetMoveVector()) {}; + + private: + Vector2D m_MoveVector; + }; + + class MITKCORE_EXPORT DisplaySetCrosshairEvent : public DisplayActionEvent + { + public: + typedef DisplaySetCrosshairEvent Self; + typedef DisplayActionEvent Superclass; + + DisplaySetCrosshairEvent() : Superclass() {} + DisplaySetCrosshairEvent(InteractionEvent* interactionEvent, const Point3D& position) + : Superclass(interactionEvent) + , m_Position(position) + { + } + virtual ~DisplaySetCrosshairEvent() {} + virtual const char* GetEventName() const override { return "DisplaySetCrosshairEvent"; } + virtual bool CheckEvent(const itk::EventObject* e) const override + { return dynamic_cast(e) != nullptr; } + virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_Position); } + const Point3D& GetPosition() const { return m_Position; } + DisplaySetCrosshairEvent(const Self& s) : Superclass(s), m_Position(s.GetPosition()) {}; + + private: + Point3D m_Position; + }; + + class MITKCORE_EXPORT DisplayZoomEvent : public DisplayActionEvent + { + public: + typedef DisplayZoomEvent Self; + typedef DisplayActionEvent Superclass; + + DisplayZoomEvent() : Superclass() {} + DisplayZoomEvent(InteractionEvent* interactionEvent, float zoomFactor, const Point2D& startCoordinate) + : Superclass(interactionEvent) + , m_ZoomFactor(zoomFactor) + , m_StartCoordinate(startCoordinate) + { + } + virtual ~DisplayZoomEvent() {} + virtual const char* GetEventName() const override { return "DisplayZoomEvent"; } + virtual bool CheckEvent(const itk::EventObject* e) const override + { return dynamic_cast(e) != nullptr; } + virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_ZoomFactor, m_StartCoordinate); } + float GetZoomFactor() const { return m_ZoomFactor; } + const Point2D& GetStartCoordinate() const { return m_StartCoordinate; } + DisplayZoomEvent(const Self& s) : Superclass(s), m_ZoomFactor(s.GetZoomFactor()), m_StartCoordinate(s.GetStartCoordinate()) {}; + + private: + float m_ZoomFactor; + Point2D m_StartCoordinate; + }; + + class MITKCORE_EXPORT DisplayScrollEvent : public DisplayActionEvent + { + public: + typedef DisplayScrollEvent Self; + typedef DisplayActionEvent Superclass; + + DisplayScrollEvent() : Superclass() {} + DisplayScrollEvent(InteractionEvent* interactionEvent, int sliceDelta) + : Superclass(interactionEvent) + , m_SliceDelta(sliceDelta) + { + } + virtual ~DisplayScrollEvent() {} + virtual const char* GetEventName() const override { return "DisplayScrollEvent"; } + virtual bool CheckEvent(const itk::EventObject* e) const override + { return dynamic_cast(e) != nullptr; } + virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_SliceDelta); } + int GetSliceDelta() const { return m_SliceDelta; } + DisplayScrollEvent(const Self& s) : Superclass(s), m_SliceDelta(s.GetSliceDelta()) {}; + + private: + int m_SliceDelta; + }; + + class MITKCORE_EXPORT DisplaySetLevelWindowEvent : public DisplayActionEvent + { + public: + typedef DisplaySetLevelWindowEvent Self; + typedef DisplayActionEvent Superclass; + + DisplaySetLevelWindowEvent() : Superclass() {} + DisplaySetLevelWindowEvent(InteractionEvent* interactionEvent, ScalarType level, ScalarType window) + : Superclass(interactionEvent) + , m_Level(level) + , m_Window(window) + { + } + virtual ~DisplaySetLevelWindowEvent() {} + virtual const char* GetEventName() const override { return "DisplaySetLevelWindowEvent"; } + virtual bool CheckEvent(const itk::EventObject* e) const override + { + return dynamic_cast(e) != nullptr; + } + virtual itk::EventObject* MakeObject() const override { return new Self(GetInteractionEvent(), m_Level, m_Window); } + ScalarType GetLevel() const { return m_Level; } + ScalarType GetWindow() const { return m_Window; } + DisplaySetLevelWindowEvent(const Self& s) : Superclass(s), m_Level(s.GetLevel()), m_Window(s.GetWindow()) {}; + + private: + ScalarType m_Level; + ScalarType m_Window; + }; + +} // end namespace + +#endif // MITKDISPLAYACTIONEVENTS_H diff --git a/Modules/Core/include/mitkDisplayInteractor.h b/Modules/Core/include/mitkDisplayInteractor.h index 42cf91b91b..26aae0c67f 100644 --- a/Modules/Core/include/mitkDisplayInteractor.h +++ b/Modules/Core/include/mitkDisplayInteractor.h @@ -1,282 +1,283 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDisplayInteractor_h #define mitkDisplayInteractor_h #include "mitkInteractionEventObserver.h" #include namespace mitk { /** *\class DisplayInteractor *@brief Observer that manages the interaction with the display. * * This includes the interaction of Zooming, Panning, Scrolling and adjusting the LevelWindow. * * @ingroup Interaction **/ /** * Inherits from mitk::InteractionEventObserver since it doesn't alter any data (only their representation), * and its actions cannot be associated with a DataNode. Also inherits from EventStateMachine */ class MITKCORE_EXPORT DisplayInteractor : public EventStateMachine, public InteractionEventObserver { public: - mitkClassMacro(DisplayInteractor, EventStateMachine) itkFactorylessNewMacro(Self) itkCloneMacro(Self) - /** - * By this function the Observer gets notified about new events. - * Here it is adapted to pass the events to the state machine in order to use - * its infrastructure. - * It also checks if event is to be accepted when it already has been processed by a DataInteractor. - */ - void Notify(InteractionEvent *interactionEvent, bool isHandled) override; + + mitkClassMacro(DisplayInteractor, EventStateMachine) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + /** + * By this function the Observer gets notified about new events. + * Here it is adapted to pass the events to the state machine in order to use + * its infrastructure. + * It also checks if event is to be accepted when it already has been processed by a DataInteractor. + */ + virtual void Notify(InteractionEvent *interactionEvent, bool isHandled) override; protected: + DisplayInteractor(); ~DisplayInteractor() override; /** * Derived function. * Connects the action names used in the state machine pattern with functions implemented within * this InteractionEventObserver. This is only necessary here because the events are processed by the state machine. */ void ConnectActionsAndFunctions() override; /** * Derived function. * Is executed when config object is set / changed. * Here it is used to read out the parameters set in the configuration file, * and set the member variables accordingly. */ void ConfigurationChanged() override; /** * Derived function. * Is executed when config object is set / changed. * Here it is used to read out the parameters set in the configuration file, * and set the member variables accordingly. */ bool FilterEvents(InteractionEvent *interactionEvent, DataNode *dataNode) override; virtual bool CheckPositionEvent(const InteractionEvent *interactionEvent); virtual bool CheckRotationPossible(const InteractionEvent *interactionEvent); virtual bool CheckSwivelPossible(const InteractionEvent *interactionEvent); /** * \brief Initializes an interaction, saves the pointers start position for further reference. */ virtual void Init(StateMachineAction *, InteractionEvent *); /** * \brief Performs panning of the data set in the render window. */ virtual void Move(StateMachineAction *, InteractionEvent *); /** * \brief Sets crosshair at clicked position* */ virtual void SetCrosshair(StateMachineAction *, InteractionEvent *); /** * \brief Increases the time step in 3d+t data */ virtual void IncreaseTimeStep(StateMachineAction *, InteractionEvent *); /** * \brief Decreases the time step in 3d+t data */ virtual void DecreaseTimeStep(StateMachineAction *, InteractionEvent *); /** * \brief Performs zooming relative to mouse/pointer movement. * * Behavior is determined by \see m_ZoomDirection and \see m_ZoomFactor. * */ virtual void Zoom(StateMachineAction *, InteractionEvent *); /** * \brief Performs scrolling relative to mouse/pointer movement. * * Behavior is determined by \see m_ScrollDirection and \see m_AutoRepeat. * */ virtual void Scroll(StateMachineAction *, InteractionEvent *); /** * \brief Scrolls one layer up */ virtual void ScrollOneDown(StateMachineAction *, InteractionEvent *); /** * \brief Scrolls one layer down */ virtual void ScrollOneUp(StateMachineAction *, InteractionEvent *); /** * \brief Adjusts the level windows relative to mouse/pointer movement. */ virtual void AdjustLevelWindow(StateMachineAction *, InteractionEvent *); /** * \brief Starts crosshair rotation */ virtual void StartRotation(StateMachineAction *, InteractionEvent *); /** * \brief Ends crosshair rotation */ virtual void EndRotation(StateMachineAction *, InteractionEvent *); /** * \brief */ virtual void Rotate(StateMachineAction *, InteractionEvent *event); virtual void Swivel(StateMachineAction *, InteractionEvent *event); /** * \brief Updates the Statusbar information with the information about the clicked position */ virtual void UpdateStatusbar(StateMachineAction *, InteractionEvent *event); /** * \brief Method to retrieve bool-value for given property from string-property * in given propertylist. */ bool GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char *propertyName, bool defaultValue); - // Typedefs - typedef std::vector SNCVector; - private: /** * @brief UpdateStatusBar * @param image3D * @param idx * @param time * @param component If the PixelType of image3D is a vector (for example a 2D velocity vector), then only one of the vector components can be * displayed at once. Setting this parameter will determine which of the vector's components will be used to determine the displayed PixelValue. * Set this to 0 for scalar images */ void UpdateStatusBar(itk::SmartPointer image3D, itk::Index<3> idx, TimeStepType time=0, int component=0); /** * \brief Coordinate of the pointer at begin of an interaction translated to mm unit */ mitk::Point2D m_StartCoordinateInMM; /** * \brief Coordinate of the pointer in the last step within an interaction. */ mitk::Point2D m_LastDisplayCoordinate; /** * \brief Coordinate of the pointer in the last step within an interaction translated to mm unit */ mitk::Point2D m_LastCoordinateInMM; /** * \brief Current coordinates of the pointer. */ mitk::Point2D m_CurrentDisplayCoordinate; /** * \brief Modifier that defines how many slices are scrolled per pixel that the mouse has moved * * This modifier defines how many slices the scene is scrolled per pixel that the mouse cursor has moved. * By default the modifier is 4. This means that when the user moves the cursor by 4 pixels in Y-direction * the scene is scrolled by one slice. If the user has moved the the cursor by 20 pixels, the scene is * scrolled by 5 slices. * * If the cursor has moved less than m_IndexToSliceModifier pixels the scene is scrolled by one slice. */ int m_IndexToSliceModifier; /** Defines behavior at end of data set. * If set to true it will restart at end of data set from the beginning. */ bool m_AutoRepeat; /** * Defines scroll behavior. * Default is up/down movement of pointer performs scrolling */ std::string m_ScrollDirection; /** * Defines how the axis of interaction influences scroll behavior. */ bool m_InvertScrollDirection; /** * Defines scroll behavior. * Default is up/down movement of pointer performs zooming */ std::string m_ZoomDirection; /** * Defines how the axis of interaction influences zoom behavior. */ bool m_InvertZoomDirection; /** * Defines how the axis of interaction influences move behavior. */ bool m_InvertMoveDirection; /** * Defines level/window behavior. * Default is left/right movement of pointer modifies the level. */ std::string m_LevelDirection; /** * Defines how the axis of interaction influences level/window behavior. */ bool m_InvertLevelWindowDirection; /** * Determines if the Observer reacts to events that already have been processed by a DataInteractor. * The default value is false. */ bool m_AlwaysReact; /** * Factor to adjust zooming speed. */ float m_ZoomFactor; ///// Members to deal with rotating slices /** * @brief m_LinkPlanes Determines if angle between crosshair remains fixed when rotating */ bool m_LinkPlanes; + typedef std::vector SNCVector; SNCVector m_RotatableSNCs; /// all SNCs that currently have CreatedWorldGeometries, that can be rotated. - SNCVector - m_SNCsToBeRotated; /// all SNCs that will be rotated (exceptions are the ones parallel to the one being clicked) + SNCVector m_SNCsToBeRotated; /// all SNCs that will be rotated (exceptions are the ones parallel to the one being clicked) Point3D m_LastCursorPosition; /// used for calculation of the rotation angle Point3D m_CenterOfRotation; /// used for calculation of the rotation angle Point2D m_ReferenceCursor; Vector3D m_RotationPlaneNormal; Vector3D m_RotationPlaneXVector; Vector3D m_RotationPlaneYVector; Vector3D m_PreviousRotationAxis; ScalarType m_PreviousRotationAngle; }; } #endif diff --git a/Modules/Core/include/mitkInteractionSchemeSwitcher.h b/Modules/Core/include/mitkInteractionSchemeSwitcher.h new file mode 100644 index 0000000000..245f4b2d8d --- /dev/null +++ b/Modules/Core/include/mitkInteractionSchemeSwitcher.h @@ -0,0 +1,111 @@ +/*=================================================================== + +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 MITKINTERACTIONSCHEMESWITCHER_H +#define MITKINTERACTIONSCHEMESWITCHER_H + +#include "MitkCoreExports.h" + +#include "mitkInteractionEventHandler.h" + +#include + +namespace mitk +{ + /*********************************************************************** + * + * \brief Class that offers a convenient way to switch between different + * interaction schemes and their different modes. + * + * This class offers the possibility to switch between the two different + * interaction schemes that are available: + * + * - MITK : The original interaction scheme + * - left mouse button : setting the cross position in the MPR view + * - middle mouse button : panning + * - right mouse button : zooming + * + * There are 3 different MITK modes that are available in the MITK scheme. + * + * - PACS : An alternative interaction scheme that behaves more like a + * PACS workstation + * - left mouse button : behavior depends on current MouseMode + * - middle mouse button : fast scrolling + * - right mouse button : level-window + * - ctrl + right button : zooming + * - shift+ right button : panning + * + * There are 5 different PACS modes that are available in the PACS scheme. + * Each mode defines the interaction that is performed on a left + * mouse button click: + * - Pointer : sets the cross position for the MPR + * - Scroll + * - Level-Window + * - Zoom + * - Pan + * + * When the interaction scheme is changed, this class sets the corresponding + * interaction .xml-files for a given interaction event handler. + * + ***********************************************************************/ + class MITKCORE_EXPORT InteractionSchemeSwitcher : public itk::Object + { + public: +#pragma GCC visibility push(default) + /** + \brief Can be observed by GUI class to update button states when type is changed programmatically. + */ + itkEventMacro(InteractionSchemeChangedEvent, itk::AnyEvent); +#pragma GCC visibility pop + + mitkClassMacroItkParent(InteractionSchemeSwitcher, itk::Object); + itkFactorylessNewMacro(Self) itkCloneMacro(Self) + + // enum of the different interaction schemes that are available + enum InteractionScheme + { + MITKStandard = 0, + MITKRotationUncoupled, + MITKRotationCoupled, + MITKSwivel, + PACSStandard, + PACSLevelWindow, + PACSPan, + PACSScroll, + PACSZoom + }; + + /** + * @brief Set the current interaction scheme of the given interaction event handler + */ + void SetInteractionScheme(mitk::InteractionEventHandler* interactionEventHandler, InteractionScheme interactionScheme); + /** + * @brief Return the current interaction scheme + */ + InteractionScheme GetInteractionScheme() const { return m_InteractionScheme; }; + + protected: + + InteractionSchemeSwitcher(); + virtual ~InteractionSchemeSwitcher() override; + + private: + + InteractionScheme m_InteractionScheme; + }; +} // namespace mitk + +#endif // MITKINTERACTIONSCHEMESWITCHER_H diff --git a/Modules/Core/include/mitkLookupTable.h b/Modules/Core/include/mitkLookupTable.h index e6f9d79f99..ccb18e3cd0 100644 --- a/Modules/Core/include/mitkLookupTable.h +++ b/Modules/Core/include/mitkLookupTable.h @@ -1,278 +1,278 @@ /*=================================================================== 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 mitkLookupTable_h #define mitkLookupTable_h #include "mitkCommon.h" #include #include #include #include #include class vtkColorTransferFunction; class vtkPiecewiseFunction; namespace mitk { /** * @brief The LookupTable class mitk wrapper for a vtkLookupTable * @ingroup DataManagement * * This class can be used to color images with a LookupTable, such as the * vtkLookupTable. * @note If you want to use this as a property for an mitk::Image, make sure * to use the mitk::LookupTableProperty and set the mitk::RenderingModeProperty * to a mode which supports lookup tables (e.g. LOOKUPTABLE_COLOR). Make * sure to check the documentation of the mitk::RenderingModeProperty. For a * code example how to use the mitk::LookupTable check the * mitkImageVtkMapper2DLookupTableTest.cpp in Core\Code\Testing. */ class MITKCORE_EXPORT LookupTable : public itk::DataObject { public: /** * @brief RawLookupTableType raw lookuptable typedef for convenience. */ typedef unsigned char RawLookupTableType; mitkClassMacroItkParent(LookupTable, itk::DataObject); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** * @brief GetVtkLookupTable Getter for the internally wrapped vtkLookupTable. */ virtual vtkSmartPointer GetVtkLookupTable() const; /** * @brief GetRawLookupTable Getter for the raw lookuptable array. */ virtual RawLookupTableType *GetRawLookupTable() const; /** * @brief SetVtkLookupTable Setter for the internal lookuptable. * @param lut The lookuptable. */ virtual void SetVtkLookupTable(vtkSmartPointer lut); /** * @brief ChangeOpacityForAll Set the opacity for all table values. * @param opacity Opacity between 0.0 and 1.0. */ virtual void ChangeOpacityForAll(float opacity); /** * @brief ChangeOpacity Set the opacity for a specific table index. * @param index The lookuptable index. * @param opacity Opacity between 0.0 and 1.0. */ virtual void ChangeOpacity(int index, float opacity); /** * @brief GetColor convenience method wrapping the vtkLookupTable::GetColor() method. * * Map one value through the lookup table and return the color as an RGB array of doubles between 0 and 1. * @param value The value you want to map. * @param rgb RGB values between 0 and 1. */ virtual void GetColor(double value, double rgb[3]); /** * @brief GetTableValue convenience method wrapping the vtkLookupTable::GetTableValue() method. * @param index The index you want to get. * @param rgba RGB values between 0 and 1. */ virtual void GetTableValue(int index, double rgba[4]); /** * @brief SetTableValue convenience method wrapping the vtkLookupTable::SetTableValue() method. * @param index The index you want to set. * @param rgba RGB values between 0 and 1. */ virtual void SetTableValue(int index, double rgba[4]); itkSetMacro(Window, float); itkSetMacro(Level, float); itkSetMacro(Opacity, float); /** * @brief equality operator implementation */ virtual bool operator==(const mitk::LookupTable &LookupTable) const; /** * @brief non equality operator implementation */ virtual bool operator!=(const LookupTable &LookupTable) const; /** * @brief implementation necessary because operator made * private in itk::Object */ virtual LookupTable &operator=(const LookupTable &LookupTable); /** * @brief Updates the output information of the current object by calling * updateOutputInformation of the data objects source object. */ void UpdateOutputInformation() override; /** * @brief Sets the requested Region to the largest possible region. * This method is not implemented, since this is the default * behavior of the itk pipeline and we do not support the * requested-region mechanism for lookup-tables */ void SetRequestedRegionToLargestPossibleRegion() override; /** * @brief Checks, if the requested region lies outside of the buffered region by * calling verifyRequestedRegion(). */ bool RequestedRegionIsOutsideOfTheBufferedRegion() override; /** * @brief Checks if the requested region is completely contained in * the buffered region. Since we always want to process the lookup * table as a whole, this method always returns true */ bool VerifyRequestedRegion() override; /** * @brief This method has no effect for lookup tables, since we do * not support the region-mechanism */ void SetRequestedRegion(const itk::DataObject *data) override; LookupTable(); ~LookupTable() override; /** * \deprecatedSince{2014_03} Please use CreateColorTransferFunction() instead */ DEPRECATED(void CreateColorTransferFunction(vtkColorTransferFunction *&colorFunction)); /** * \deprecatedSince{2014_03} Please use CreateOpacityTransferFunction() instead */ DEPRECATED(void CreateOpacityTransferFunction(vtkPiecewiseFunction *&opacityFunction)); /** * \deprecatedSince{2014_03} Please use CreateGradientTransferFunction() instead */ DEPRECATED(void CreateGradientTransferFunction(vtkPiecewiseFunction *&gradientFunction)); vtkSmartPointer CreateColorTransferFunction(); vtkSmartPointer CreateOpacityTransferFunction(); vtkSmartPointer CreateGradientTransferFunction(); /** * @brief The LookupTableType enum for different predefined lookup tables. * * \li GRAYSCALE Our default level-window (sometimes referred to as window-level by other sources) setup for a test * image looks like this: * \image html ExampleLevelWindowColor.png * \li INVERSE_GRAYSCALE Inverse LookupTable of GRAYSCALE. * \li HOT_IRON A LookupTable for red colors. * \li JET A LookupTable for JET color rendering. * \li LEGACY_BINARY A LookupTable for binary images. * \li LEGACY_RAINBOW_COLOR A rainbow-like LookupTable. * \li MULTILABEL A LookupTable for multilabel images. * \li PET_COLOR A LookupTable for PET color rendering. * \li PET_20 A LookupTable for PET_20 color rendering. * * The different LookupTableTypes can be applied in the MitkWorkbench via right-clicking * on an image and choosing a color map. */ enum LookupTableType { GRAYSCALE, INVERSE_GRAYSCALE, HOT_IRON, JET, JET_TRANSPARENT, PLASMA, INFERNO, VIRIDIS, MAGMA, LEGACY_BINARY, LEGACY_RAINBOW_COLOR, MULTILABEL, PET_COLOR, PET_20 }; - static const char *const typenameList[]; + static std::vector typenameList; /** * @brief Set the look-up table type by enum (or integer). * @details Returns if the given type doesn't exist. Only changes the type if it is different * from the current one. */ virtual void SetType(const LookupTableType type); /** * @brief Set the look-up table type by string. * @details Returns if the given type doesn't exist. Only changes the type if it is different * from the current one. */ virtual void SetType(const std::string &typeName); /** * @brief Return the current look-up table type. */ virtual LookupTableType GetActiveType() const; /** * @brief Return the current look-up table type as a string. */ virtual std::string GetActiveTypeAsString() const; protected: void PrintSelf(std::ostream &os, itk::Indent indent) const override; LookupTable(const LookupTable &other); virtual void BuildGrayScaleLookupTable(); virtual void BuildLegacyBinaryLookupTable(); virtual void BuildLegacyRainbowColorLookupTable(); virtual void BuildInverseGrayScaleLookupTable(); virtual void BuildHotIronLookupTable(); virtual void BuildPlasmaLookupTable(); virtual void BuildInfernoLookupTable(); virtual void BuildViridisLookupTable(); virtual void BuildMagmaLookupTable(); virtual void BuildJetLookupTable(bool transparent = false); virtual void BuildPETColorLookupTable(); virtual void BuildPET20LookupTable(); virtual void BuildMultiLabelLookupTable(); vtkSmartPointer m_LookupTable; float m_Window; float m_Level; float m_Opacity; - LookupTableType m_type; + LookupTableType m_Type; private: itk::LightObject::Pointer InternalClone() const override; }; } // namespace mitk #endif /* mitkLookupTable_h */ diff --git a/Modules/Core/include/mitkSliceNavigationController.h b/Modules/Core/include/mitkSliceNavigationController.h index c03c961ead..89f122fe2a 100644 --- a/Modules/Core/include/mitkSliceNavigationController.h +++ b/Modules/Core/include/mitkSliceNavigationController.h @@ -1,518 +1,518 @@ /*=================================================================== 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 SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #define SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #include "mitkBaseController.h" #include "mitkMessage.h" #include "mitkRenderingManager.h" #include "mitkTimeGeometry.h" #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include "mitkDataStorage.h" #include "mitkRestorePlanePositionOperation.h" #include #include // DEPRECATED #include namespace mitk { #define mitkTimeSlicedGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT DEPRECATED(classname) : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } #define mitkTimeGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT classname : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } class PlaneGeometry; class BaseGeometry; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a BaseGeometry or a TimeGeometry as input world geometry * (TODO what are the exact requirements?) and generates a TimeGeometry * as output. The TimeGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of PlaneGeometries. One of these PlaneGeometries is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * PlaneGeometry from the TimeGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // BaseGeometry::ConstPointer) * sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITKCORE_EXPORT SliceNavigationController : public BaseController { public: mitkClassMacro(SliceNavigationController, BaseController); // itkFactorylessNewMacro(Self) // mitkNewMacro1Param(Self, const char *); itkNewMacro(Self); // itkCloneMacro(Self) /** * \brief Possible view directions, \a Original will uses * the PlaneGeometry instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldGeometry). */ enum ViewDirection { Axial, Sagittal, Frontal, Original }; /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. */ void SetInputWorldGeometry3D(const mitk::BaseGeometry *geometry); itkGetConstObjectMacro(InputWorldGeometry3D, mitk::BaseGeometry); /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void SetInputWorldGeometry(const mitk::TimeSlicedGeometry *geometry)); /** * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(TimeSlicedGeometry *GetInputWorldGeometry()); void SetInputWorldTimeGeometry(const mitk::TimeGeometry *geometry); itkGetConstObjectMacro(InputWorldTimeGeometry, mitk::TimeGeometry); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, mitk::TimeGeometry); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(ViewDirection, ViewDirection); itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(DefaultViewDirection, ViewDirection); itkGetEnumMacro(DefaultViewDirection, ViewDirection); const char *GetViewDirectionAsString() const; virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); /** * \brief Set the RenderingManager to be used * * If \a nullptr, the default RenderingManager will be used. */ itkSetObjectMacro(RenderingManager, RenderingManager); mitk::RenderingManager *GetRenderingManager() const; #pragma GCC visibility push(default) itkEventMacro(UpdateEvent, itk::AnyEvent); #pragma GCC visibility pop class MITKCORE_EXPORT TimeGeometryEvent : public itk::AnyEvent { public: typedef TimeGeometryEvent Self; typedef itk::AnyEvent Superclass; TimeGeometryEvent(TimeGeometry *aTimeGeometry, unsigned int aPos) : m_TimeGeometry(aTimeGeometry), m_Pos(aPos) {} ~TimeGeometryEvent() override {} const char *GetEventName() const override { return "TimeGeometryEvent"; } bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); } ::itk::EventObject *MakeObject() const override { return new Self(m_TimeGeometry, m_Pos); } TimeGeometry *GetTimeGeometry() const { return m_TimeGeometry; } unsigned int GetPos() const { return m_Pos; } private: TimeGeometry::Pointer m_TimeGeometry; unsigned int m_Pos; // TimeGeometryEvent(const Self&); void operator=(const Self &); // just hide }; /** * \deprecatedSince{2013_09} Please use TimeGeometryEvent instead: For additional information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(typedef TimeGeometryEvent TimeSlicedGeometryEvent); mitkTimeGeometryEventMacro(GeometrySendEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryUpdateEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryTimeEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometrySliceEvent, TimeGeometryEvent); template void ConnectGeometrySendEvent(T *receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); unsigned long tag = AddObserver(GeometrySendEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometryUpdateEvent(T *receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); unsigned long tag = AddObserver(GeometryUpdateEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometrySliceEvent(T *receiver, bool connectSendEvent = true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); unsigned long tag = AddObserver(GeometrySliceEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if (connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryTimeEvent(T *receiver, bool connectSendEvent = true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); unsigned long tag = AddObserver(GeometryTimeEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if (connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryEvents(T *receiver) { // connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } // use a templated method to get the right offset when casting to void* template void Disconnect(T *receiver) { auto i = m_ReceiverToObserverTagsMap.find(static_cast(receiver)); if (i == m_ReceiverToObserverTagsMap.end()) return; const std::list &tags = i->second; for (auto tagIter = tags.begin(); tagIter != tags.end(); ++tagIter) { RemoveObserver(*tagIter); } m_ReceiverToObserverTagsMap.erase(i); } - Message<> crosshairPositionEvent; + Message1 SetCrosshairEvent; /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ virtual void SetGeometry(const itk::EventObject &geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometrySlice(const itk::EventObject &geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometryTime(const itk::EventObject &geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ void SelectSliceByPoint(const mitk::Point3D &point); /** \brief Returns the TimeGeometry created by the SNC. */ mitk::TimeGeometry *GetCreatedWorldGeometry(); /** \brief Returns the BaseGeometry of the currently selected time step. */ const mitk::BaseGeometry *GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * BaseGeometry (if existent). */ const mitk::PlaneGeometry *GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ void SetRenderer(BaseRenderer *renderer); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns nullptr if no * BaseRenderer has been specified*/ BaseRenderer *GetRenderer() const; /** \brief Re-orients the slice stack. All slices will be oriented to the given normal vector. The given point (world coordinates) defines the selected slice. Careful: The resulting axis vectors are not clearly defined this way. If you want to define them clearly, use ReorientSlices (const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1). */ void ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &normal); /** \brief Re-orients the slice stack so that all planes are oriented according to the * given axis vectors. The given Point eventually defines selected slice. */ void ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1); void ExecuteOperation(Operation *operation) override; /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); protected: SliceNavigationController(); ~SliceNavigationController() override; mitk::BaseGeometry::ConstPointer m_InputWorldGeometry3D; mitk::TimeGeometry::ConstPointer m_InputWorldTimeGeometry; mitk::TimeGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer *m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; typedef std::map> ObserverTagsMapType; ObserverTagsMapType m_ReceiverToObserverTagsMap; }; } // namespace mitk #endif /* SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F */ diff --git a/Modules/Core/include/mitkStdDisplayActionEventHandler.h b/Modules/Core/include/mitkStdDisplayActionEventHandler.h new file mode 100644 index 0000000000..76758df9eb --- /dev/null +++ b/Modules/Core/include/mitkStdDisplayActionEventHandler.h @@ -0,0 +1,41 @@ +/*=================================================================== + +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 "mitkDisplayActionEventHandler.h" + +namespace mitk +{ + class MITKCORE_EXPORT StdDisplayActionEventHandler : public DisplayActionEventHandler + { + public: + + /** + * @brief Initializes common standard display actions by using the default display action event 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(); + }; +} // end namespace mitk + +#endif // MITKSTDDISPLAYACTIONEVENTHANDLER_H diff --git a/Modules/Core/include/mitkStdFunctionCommand.h b/Modules/Core/include/mitkStdFunctionCommand.h new file mode 100644 index 0000000000..e1ce8dfc2a --- /dev/null +++ b/Modules/Core/include/mitkStdFunctionCommand.h @@ -0,0 +1,95 @@ +/*=================================================================== + +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 MITKSTDFUNCTIONCOMMAND_H +#define MITKSTDFUNCTIONCOMMAND_H + +#include + +// itk +#include + +// c++ +#include + +namespace mitk +{ + // define custom command to accept std::functions as "filter" and as "action" + class MITKCORE_EXPORT StdFunctionCommand : public itk::Command + { + public: + using Self = StdFunctionCommand; + using Pointer = itk::SmartPointer; + + using FilterFunction = std::function; + using ActionFunction = std::function; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(StdFunctionCommand, itk::Command); + + void SetCommandFilter(FilterFunction stdFunctionFilter) + { + m_StdFilterFunction = stdFunctionFilter; + } + + void SetCommandAction(ActionFunction stdFunctionAction) + { + m_StdActionFunction = stdFunctionAction; + } + + virtual void Execute(Object*, const itk::EventObject& event) override + { + if (m_StdFilterFunction && m_StdActionFunction) + { + if (m_StdFilterFunction(event)) + { + m_StdActionFunction(event); + } + } + } + + virtual void Execute(const Object*, const itk::EventObject& event) override + { + if (m_StdFilterFunction && m_StdActionFunction) + { + if (m_StdFilterFunction(event)) + { + m_StdActionFunction(event); + } + } + } + + protected: + FilterFunction m_StdFilterFunction; + ActionFunction m_StdActionFunction; + + StdFunctionCommand() + : m_StdFilterFunction(nullptr) + , m_StdActionFunction(nullptr) + {} + + virtual ~StdFunctionCommand() {} + + private: + ITK_DISALLOW_COPY_AND_ASSIGN(StdFunctionCommand); + }; + +} // end namespace mitk + +#endif // MITKSTDFUNCTIONCOMMAND_H diff --git a/Modules/Core/include/mitkStepper.h b/Modules/Core/include/mitkStepper.h index d86c668fc1..16b51ebf87 100644 --- a/Modules/Core/include/mitkStepper.h +++ b/Modules/Core/include/mitkStepper.h @@ -1,146 +1,148 @@ /*=================================================================== 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 STEPPER_H_HEADER_INCLUDED_C1E77191 #define STEPPER_H_HEADER_INCLUDED_C1E77191 #include "mitkNumericTypes.h" #include #include #include #include #include namespace mitk { /** * \brief Helper class to step through a list * * A helper class to step through a list. Does not contain the list, just the * position in the list (between 0 and GetSteps()). Provides methods like * First (go to the first element), Next (go to the next one), etc. * * Besides the actual number of steps, the stepper can also hold a stepping * range, indicating the scalar values corresponding to the covered steps. * For example, steppers are generally used to slice a dataset with a plane; * Hereby, Steps indicates the total number of steps (positions) available for * the plane, Pos indicates the current step, and Range indicates the physical * minimum and maximum values for the plane, in this case a value in mm. * * The range can also be supplied with a unit name (a string) which can be * used by classes providing information about the stepping (e.g. graphical * sliders). * * \ingroup NavigationControl */ class MITKCORE_EXPORT Stepper : public itk::Object { public: mitkClassMacroItkParent(Stepper, itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkGetConstMacro(Pos, unsigned int); virtual void SetPos(unsigned int pos) { // copied from itkMacro.h, itkSetClampMacro(...) unsigned int newPos; if (m_Steps != 0) { newPos = (pos > m_Steps - 1 ? m_Steps - 1 : pos); } else { newPos = 0; } if (this->m_Pos != newPos) { this->m_Pos = newPos; this->Modified(); } } itkGetConstMacro(Steps, unsigned int); itkSetMacro(Steps, unsigned int); itkGetConstMacro(AutoRepeat, bool); itkSetMacro(AutoRepeat, bool); itkBooleanMacro(AutoRepeat); /** Causes the stepper to shift direction when the boundary is reached */ itkSetMacro(PingPong, bool); itkGetConstMacro(PingPong, bool); itkBooleanMacro(PingPong); /** If set to true, the Next() decreases the stepper and Previous() * decreases it */ itkSetMacro(InverseDirection, bool); itkGetConstMacro(InverseDirection, bool); itkBooleanMacro(InverseDirection); void SetRange(ScalarType min, ScalarType max); void InvalidateRange(); ScalarType GetRangeMin() const; ScalarType GetRangeMax() const; bool HasValidRange() const; void RemoveRange(); bool HasRange() const; void SetUnitName(const char *unitName); const char *GetUnitName() const; void RemoveUnitName(); bool HasUnitName() const; virtual void Next(); virtual void Previous(); + virtual void MoveSlice(int sliceDelta); + virtual void First(); virtual void Last(); protected: Stepper(); ~Stepper() override; void Increase(); void Decrease(); unsigned int m_Pos; unsigned int m_Steps; bool m_AutoRepeat; bool m_PingPong; bool m_InverseDirection; ScalarType m_RangeMin; ScalarType m_RangeMax; bool m_RangeValid; bool m_HasRange; std::string m_UnitName; bool m_HasUnitName; }; } // namespace mitk #endif /* STEPPER_H_HEADER_INCLUDED_C1E77191 */ diff --git a/Modules/Core/resource/Interactions/DisplayConfigMITK.xml b/Modules/Core/resource/Interactions/DisplayConfigMITK.xml index f5a8e80498..269d079e79 100644 --- a/Modules/Core/resource/Interactions/DisplayConfigMITK.xml +++ b/Modules/Core/resource/Interactions/DisplayConfigMITK.xml @@ -1,59 +1,59 @@ - - - + + + diff --git a/Modules/Core/resource/Interactions/DisplayConfigMITKRotation.xml b/Modules/Core/resource/Interactions/DisplayConfigMITKRotation.xml index f8fc7c3ede..94f1a24f3d 100644 --- a/Modules/Core/resource/Interactions/DisplayConfigMITKRotation.xml +++ b/Modules/Core/resource/Interactions/DisplayConfigMITKRotation.xml @@ -1,55 +1,53 @@ - - diff --git a/Modules/Core/resource/Interactions/DisplayConfigMITKRotationUnCoupled.xml b/Modules/Core/resource/Interactions/DisplayConfigMITKRotationUnCoupled.xml index 852aafa2de..43e68d7d36 100644 --- a/Modules/Core/resource/Interactions/DisplayConfigMITKRotationUnCoupled.xml +++ b/Modules/Core/resource/Interactions/DisplayConfigMITKRotationUnCoupled.xml @@ -1,55 +1,53 @@ - + - - diff --git a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp index aeea570d69..5fd526aab0 100644 --- a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp +++ b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp @@ -1,659 +1,658 @@ /*=================================================================== 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 "mitkSliceNavigationController.h" #include "mitkAction.h" #include "mitkBaseRenderer.h" #include "mitkCrosshairPositionEvent.h" #include "mitkInteractionConst.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkPlaneGeometry.h" #include "mitkProportionalTimeGeometry.h" #include "mitkArbitraryTimeGeometry.h" #include "mitkRenderingManager.h" #include "mitkSlicedGeometry3D.h" #include "mitkVtkPropRenderer.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkInteractionConst.h" #include "mitkNodePredicateDataType.h" #include "mitkOperationEvent.h" #include "mitkPixelTypeMultiplex.h" #include "mitkPlaneOperation.h" #include "mitkPointOperation.h" #include "mitkStatusBar.h" #include "mitkUndoController.h" #include "mitkApplyTransformMatrixOperation.h" #include "mitkMemoryUtilities.h" #include namespace mitk { SliceNavigationController::SliceNavigationController() : BaseController(), m_InputWorldGeometry3D( mitk::BaseGeometry::ConstPointer() ), m_InputWorldTimeGeometry( mitk::TimeGeometry::ConstPointer() ), m_CreatedWorldGeometry( mitk::TimeGeometry::Pointer() ), m_ViewDirection(Axial), m_DefaultViewDirection(Axial), m_RenderingManager( mitk::RenderingManager::Pointer() ), m_Renderer( nullptr ), m_Top(false), m_FrontSide(false), m_Rotated(false), m_BlockUpdate(false), m_SliceLocked(false), m_SliceRotationLocked(false), m_OldPos(0) { typedef itk::SimpleMemberCommand SNCCommandType; SNCCommandType::Pointer sliceStepperChangedCommand, timeStepperChangedCommand; sliceStepperChangedCommand = SNCCommandType::New(); timeStepperChangedCommand = SNCCommandType::New(); sliceStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendSlice); timeStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendTime); m_Slice->AddObserver(itk::ModifiedEvent(), sliceStepperChangedCommand); m_Time->AddObserver(itk::ModifiedEvent(), timeStepperChangedCommand); m_Slice->SetUnitName("mm"); m_Time->SetUnitName("ms"); m_Top = false; m_FrontSide = false; m_Rotated = false; } SliceNavigationController::~SliceNavigationController() {} void SliceNavigationController::SetInputWorldGeometry3D(const BaseGeometry *geometry) { if ( geometry != nullptr ) { if (geometry->GetBoundingBox()->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldGeometry3D != geometry) { m_InputWorldGeometry3D = geometry; m_InputWorldTimeGeometry = mitk::TimeGeometry::ConstPointer(); this->Modified(); } } void SliceNavigationController::SetInputWorldTimeGeometry(const TimeGeometry *geometry) { if ( geometry != nullptr ) { if (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldTimeGeometry != geometry) { m_InputWorldTimeGeometry = geometry; m_InputWorldGeometry3D = mitk::BaseGeometry::ConstPointer(); this->Modified(); } } RenderingManager *SliceNavigationController::GetRenderingManager() const { mitk::RenderingManager *renderingManager = m_RenderingManager.GetPointer(); if (renderingManager != nullptr) return renderingManager; if ( m_Renderer != nullptr ) { renderingManager = m_Renderer->GetRenderingManager(); if (renderingManager != nullptr) return renderingManager; } return mitk::RenderingManager::GetInstance(); } void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } const char *SliceNavigationController::GetViewDirectionAsString() const { const char *viewDirectionString; switch (m_ViewDirection) { case SliceNavigationController::Axial: viewDirectionString = "Axial"; break; case SliceNavigationController::Sagittal: viewDirectionString = "Sagittal"; break; case SliceNavigationController::Frontal: viewDirectionString = "Coronal"; break; case SliceNavigationController::Original: viewDirectionString = "Original"; break; default: viewDirectionString = "No View Direction Available"; break; } return viewDirectionString; } void SliceNavigationController::Update() { if (!m_BlockUpdate) { if (m_ViewDirection == Sagittal) { this->Update(Sagittal, true, true, false); } else if (m_ViewDirection == Frontal) { this->Update(Frontal, false, true, false); } else if (m_ViewDirection == Axial) { this->Update(Axial, false, false, true); } else { this->Update(m_ViewDirection); } } } void SliceNavigationController::Update(SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated) { TimeGeometry::ConstPointer worldTimeGeometry = m_InputWorldTimeGeometry; if (m_BlockUpdate || (m_InputWorldTimeGeometry.IsNull() && m_InputWorldGeometry3D.IsNull()) || ((worldTimeGeometry.IsNotNull()) && (worldTimeGeometry->CountTimeSteps() == 0))) { return; } m_BlockUpdate = true; if (m_InputWorldTimeGeometry.IsNotNull() && m_LastUpdateTime < m_InputWorldTimeGeometry->GetMTime()) { Modified(); } if (m_InputWorldGeometry3D.IsNotNull() && m_LastUpdateTime < m_InputWorldGeometry3D->GetMTime()) { Modified(); } this->SetViewDirection(viewDirection); this->SetTop(top); this->SetFrontSide(frontside); this->SetRotated(rotated); if (m_LastUpdateTime < GetMTime()) { m_LastUpdateTime = GetMTime(); // initialize the viewplane SlicedGeometry3D::Pointer slicedWorldGeometry = SlicedGeometry3D::Pointer(); BaseGeometry::ConstPointer currentGeometry = BaseGeometry::ConstPointer(); if (m_InputWorldTimeGeometry.IsNotNull()) if (m_InputWorldTimeGeometry->IsValidTimeStep(GetTime()->GetPos())) currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(GetTime()->GetPos()); else currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(0); else currentGeometry = m_InputWorldGeometry3D; m_CreatedWorldGeometry = mitk::TimeGeometry::Pointer(); switch (viewDirection) { case Original: if (worldTimeGeometry.IsNotNull()) { m_CreatedWorldGeometry = worldTimeGeometry->Clone(); worldTimeGeometry = m_CreatedWorldGeometry.GetPointer(); slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry.IsNotNull()) { break; } } else { const auto *worldSlicedGeometry = dynamic_cast(currentGeometry.GetPointer()); if ( worldSlicedGeometry != nullptr ) { slicedWorldGeometry = static_cast(currentGeometry->Clone().GetPointer()); break; } } slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::None, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Axial: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Axial, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Frontal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Frontal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Sagittal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Sagittal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; default: itkExceptionMacro("unknown ViewDirection"); } m_Slice->SetPos(0); m_Slice->SetSteps((int)slicedWorldGeometry->GetSlices()); if ( worldTimeGeometry.IsNull() ) { auto createdTimeGeometry = ProportionalTimeGeometry::New(); createdTimeGeometry->Initialize( slicedWorldGeometry, 1 ); m_CreatedWorldGeometry = createdTimeGeometry; m_Time->SetSteps(0); m_Time->SetPos(0); m_Time->InvalidateRange(); } else { m_BlockUpdate = true; m_Time->SetSteps(worldTimeGeometry->CountTimeSteps()); m_Time->SetPos(0); const TimeBounds &timeBounds = worldTimeGeometry->GetTimeBounds(); m_Time->SetRange(timeBounds[0], timeBounds[1]); m_BlockUpdate = false; const auto currentTemporalPosition = this->GetTime()->GetPos(); assert( worldTimeGeometry->GetGeometryForTimeStep( currentTemporalPosition ).IsNotNull() ); if ( dynamic_cast( worldTimeGeometry.GetPointer() ) != nullptr ) { const TimePointType minimumTimePoint = worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition ); const TimePointType stepDuration = worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition + 1 ) - minimumTimePoint; auto createdTimeGeometry = ProportionalTimeGeometry::New(); createdTimeGeometry->Initialize( slicedWorldGeometry, worldTimeGeometry->CountTimeSteps() ); createdTimeGeometry->SetFirstTimePoint( minimumTimePoint ); createdTimeGeometry->SetStepDuration( stepDuration ); m_CreatedWorldGeometry = createdTimeGeometry; } else { auto createdTimeGeometry = mitk::ArbitraryTimeGeometry::New(); const TimeStepType numberOfTimeSteps = worldTimeGeometry->CountTimeSteps(); createdTimeGeometry->ReserveSpaceForGeometries( numberOfTimeSteps ); for ( TimeStepType i = 0; i < numberOfTimeSteps; ++i ) { const BaseGeometry::Pointer clonedGeometry = slicedWorldGeometry->Clone().GetPointer(); const auto bounds = worldTimeGeometry->GetTimeBounds( i ); createdTimeGeometry->AppendNewTimeStep( clonedGeometry, bounds[0], bounds[1]); } createdTimeGeometry->Update(); m_CreatedWorldGeometry = createdTimeGeometry; } } } // unblock update; we may do this now, because if m_BlockUpdate was already // true before this method was entered, then we will never come here. m_BlockUpdate = false; // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry and time/slice data. this->SendCreatedWorldGeometry(); this->SendSlice(); this->SendTime(); // Adjust the stepper range of slice stepper according to geometry this->AdjustSliceStepperRange(); } void SliceNavigationController::SendCreatedWorldGeometry() { // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry. if (!m_BlockUpdate) { this->InvokeEvent(GeometrySendEvent(m_CreatedWorldGeometry, 0)); } } void SliceNavigationController::SendCreatedWorldGeometryUpdate() { if (!m_BlockUpdate) { this->InvokeEvent(GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); } } void SliceNavigationController::SendSlice() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); - // send crosshair event - crosshairPositionEvent.Send(); - // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SendTime() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos())); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SetGeometry(const itk::EventObject &) {} void SliceNavigationController::SetGeometryTime(const itk::EventObject &geometryTimeEvent) { if (m_CreatedWorldGeometry.IsNull()) { return; } const auto *timeEvent = dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >(&geometryTimeEvent); assert( timeEvent != nullptr ); TimeGeometry *timeGeometry = timeEvent->GetTimeGeometry(); assert( timeGeometry != nullptr ); auto timeStep = (int)timeEvent->GetPos(); ScalarType timeInMS; timeInMS = timeGeometry->TimeStepToTimePoint(timeStep); timeStep = m_CreatedWorldGeometry->TimePointToTimeStep(timeInMS); this->GetTime()->SetPos(timeStep); } void SliceNavigationController::SetGeometrySlice(const itk::EventObject &geometrySliceEvent) { const auto *sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent!=nullptr); this->GetSlice()->SetPos(sliceEvent->GetPos()); } void SliceNavigationController::SelectSliceByPoint(const Point3D &point) { if (m_CreatedWorldGeometry.IsNull()) { return; } //@todo add time to PositionEvent and use here!! SlicedGeometry3D *slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry) { int bestSlice = -1; double bestDistance = itk::NumericTraits::max(); int s, slices; slices = slicedWorldGeometry->GetSlices(); if (slicedWorldGeometry->GetEvenlySpaced()) { mitk::PlaneGeometry *plane = slicedWorldGeometry->GetPlaneGeometry(0); const Vector3D &direction = slicedWorldGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project(point, projectedPoint); // Check whether the point is somewhere within the slice stack volume; // otherwise, the default slice (0) will be selected if (direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0) { bestSlice = (int)(plane->Distance(point) / slicedWorldGeometry->GetSpacing()[2] + 0.5); } } else { Point3D projectedPoint; for (s = 0; s < slices; ++s) { slicedWorldGeometry->GetPlaneGeometry(s)->Project(point, projectedPoint); const Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if (currentDistance < bestDistance) { bestDistance = currentDistance; bestSlice = s; } } } if (bestSlice >= 0) { this->GetSlice()->SetPos(bestSlice); } else { this->GetSlice()->SetPos(0); } this->SendCreatedWorldGeometryUpdate(); + // send crosshair event + SetCrosshairEvent.Send(point); } } void SliceNavigationController::ReorientSlices(const Point3D &point, const Vector3D &normal) { if (m_CreatedWorldGeometry.IsNull()) { return; } PlaneOperation op(OpORIENT, point, normal); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } void SliceNavigationController::ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1) { if (m_CreatedWorldGeometry) { PlaneOperation op(OpORIENT, point, axisVec0, axisVec1); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } } mitk::TimeGeometry *SliceNavigationController::GetCreatedWorldGeometry() { return m_CreatedWorldGeometry; } const mitk::BaseGeometry *SliceNavigationController::GetCurrentGeometry3D() { if (m_CreatedWorldGeometry.IsNotNull()) { return m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()); } else { return nullptr; } } const mitk::PlaneGeometry *SliceNavigationController::GetCurrentPlaneGeometry() { const auto *slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); if (slicedGeometry) { const mitk::PlaneGeometry *planeGeometry = (slicedGeometry->GetPlaneGeometry(this->GetSlice()->GetPos())); return planeGeometry; } else { return nullptr; } } void SliceNavigationController::SetRenderer(BaseRenderer *renderer) { m_Renderer = renderer; } BaseRenderer *SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { const auto *slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); const Vector3D &direction = slicedGeometry->GetDirectionVector(); int c = 0; int i, k = 0; for (i = 0; i < 3; ++i) { if (fabs(direction[i]) < 0.000000001) { ++c; } else { k = i; } } if (c == 2) { ScalarType min = slicedGeometry->GetOrigin()[k]; ScalarType max = min + slicedGeometry->GetExtentInMM(k); m_Slice->SetRange(min, max); } else { m_Slice->InvalidateRange(); } } void SliceNavigationController::ExecuteOperation(Operation *operation) { // switch on type // - select best slice for a given point // - rotate created world geometry according to Operation->SomeInfo() if (!operation || m_CreatedWorldGeometry.IsNull()) { return; } switch (operation->GetOperationType()) { case OpMOVE: // should be a point operation { if (!m_SliceLocked) // do not move the cross position { // select a slice auto *po = dynamic_cast(operation); if (po && po->GetIndex() == -1) { this->SelectSliceByPoint(po->GetPoint()); } else if (po && po->GetIndex() != -1) // undo case because index != -1, index holds the old position of this slice { this->GetSlice()->SetPos(po->GetIndex()); } } break; } case OpRESTOREPLANEPOSITION: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } case OpAPPLYTRANSFORMMATRIX: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } default: { // do nothing break; } } } } // namespace diff --git a/Modules/Core/src/Controllers/mitkStepper.cpp b/Modules/Core/src/Controllers/mitkStepper.cpp index cdecc526e3..14e980a2dd 100644 --- a/Modules/Core/src/Controllers/mitkStepper.cpp +++ b/Modules/Core/src/Controllers/mitkStepper.cpp @@ -1,180 +1,209 @@ /*=================================================================== 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 "mitkStepper.h" mitk::Stepper::Stepper() : m_Pos(0), m_Steps(0), m_AutoRepeat(false), m_PingPong(false), m_InverseDirection(false), m_RangeMin(0.0), m_RangeMax(-1.0), m_RangeValid(false), m_HasRange(false), m_HasUnitName(false) { } mitk::Stepper::~Stepper() { } void mitk::Stepper::SetRange(ScalarType min, ScalarType max) { m_RangeMin = min; m_RangeMax = max; m_HasRange = true; m_RangeValid = true; this->Modified(); } void mitk::Stepper::InvalidateRange() { m_HasRange = true; m_RangeValid = false; this->Modified(); } mitk::ScalarType mitk::Stepper::GetRangeMin() const { return m_RangeMin; } mitk::ScalarType mitk::Stepper::GetRangeMax() const { return m_RangeMax; } void mitk::Stepper::RemoveRange() { m_HasRange = false; this->Modified(); } bool mitk::Stepper::HasValidRange() const { return (m_HasRange && m_RangeValid); } bool mitk::Stepper::HasRange() const { return m_HasRange; } void mitk::Stepper::SetUnitName(const char *unitName) { m_UnitName = std::string(unitName); m_HasUnitName = true; this->Modified(); } const char *mitk::Stepper::GetUnitName() const { return m_UnitName.c_str(); } void mitk::Stepper::RemoveUnitName() { m_HasUnitName = false; this->Modified(); } bool mitk::Stepper::HasUnitName() const { return m_HasUnitName; } void mitk::Stepper::Increase() { if (this->GetPos() < this->GetSteps() - 1) { this->SetPos(this->GetPos() + 1); } else if (m_AutoRepeat) { if (!m_PingPong) { this->SetPos(0); } else { m_InverseDirection = true; if (this->GetPos() > 0) { this->SetPos(this->GetPos() - 1); } } } } void mitk::Stepper::Decrease() { if (this->GetPos() > 0) { this->SetPos(this->GetPos() - 1); } else if (m_AutoRepeat) { if (!m_PingPong) { this->SetPos(this->GetSteps() - 1); } else { m_InverseDirection = false; if (this->GetPos() < this->GetSteps() - 1) { this->SetPos(this->GetPos() + 1); } } } } void mitk::Stepper::Next() { if (!m_InverseDirection) { this->Increase(); } else { this->Decrease(); } } void mitk::Stepper::Previous() { if (!m_InverseDirection) { this->Decrease(); } else { this->Increase(); } } +void mitk::Stepper::MoveSlice(int sliceDelta) +{ + int newPosition = this->GetPos() + sliceDelta; + // if auto repeat is on, increasing continues at the first slice if the last slice was reached and vice versa + int maxSlices = this->GetSteps(); + if (m_AutoRepeat) + { + while (newPosition < 0) + { + newPosition += maxSlices; + } + while (newPosition >= maxSlices) + { + newPosition -= maxSlices; + } + } + else + { + // if the new slice is below 0 we still show slice 0 + // due to the stepper using unsigned int we have to do this ourselves + if (newPosition < 1) + { + newPosition = 0; + } + } + + this->SetPos(newPosition); +} + void mitk::Stepper::First() { this->SetPos(0); } void mitk::Stepper::Last() { this->SetPos(this->GetSteps() - 1); } diff --git a/Modules/Core/src/DataManagement/mitkDataStorage.cpp b/Modules/Core/src/DataManagement/mitkDataStorage.cpp index f25faaa1b8..6f0f32f2ad 100644 --- a/Modules/Core/src/DataManagement/mitkDataStorage.cpp +++ b/Modules/Core/src/DataManagement/mitkDataStorage.cpp @@ -1,574 +1,588 @@ /*=================================================================== 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 "mitkDataStorage.h" #include "itkCommand.h" #include "itkMutexLockHolder.h" #include "mitkDataNode.h" #include "mitkGroupTagProperty.h" #include "mitkImage.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include "mitkArbitraryTimeGeometry.h" mitk::DataStorage::DataStorage() : itk::Object(), m_BlockNodeModifiedEvents(false) { } mitk::DataStorage::~DataStorage() { ///// we can not call GetAll() in destructor, because it is implemented in a subclass // SetOfObjects::ConstPointer all = this->GetAll(); // for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) // this->RemoveListeners(it->Value()); // m_NodeModifiedObserverTags.clear(); // m_NodeDeleteObserverTags.clear(); } void mitk::DataStorage::Add(DataNode *node, DataNode *parent) { DataStorage::SetOfObjects::Pointer parents = DataStorage::SetOfObjects::New(); if (parent != nullptr) //< Return empty set if parent is null parents->InsertElement(0, parent); this->Add(node, parents); } void mitk::DataStorage::Remove(const DataStorage::SetOfObjects *nodes) { if (nodes == nullptr) return; for (DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++) this->Remove(it.Value()); } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::GetSubset(const NodePredicateBase *condition) const { DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), condition); return result; } mitk::DataNode *mitk::DataStorage::GetNamedNode(const char *name) const { if (name == nullptr) return nullptr; StringProperty::Pointer s(StringProperty::New(name)); NodePredicateProperty::Pointer p = NodePredicateProperty::New("name", s); DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p); if (rs->Size() >= 1) return rs->GetElement(0); else return nullptr; } mitk::DataNode *mitk::DataStorage::GetNode(const NodePredicateBase *condition) const { if (condition == nullptr) return nullptr; DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(condition); if (rs->Size() >= 1) return rs->GetElement(0); else return nullptr; } mitk::DataNode *mitk::DataStorage::GetNamedDerivedNode(const char *name, const DataNode *sourceNode, bool onlyDirectDerivations) const { if (name == nullptr) return nullptr; StringProperty::Pointer s(StringProperty::New(name)); NodePredicateProperty::Pointer p = NodePredicateProperty::New("name", s); DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, p, onlyDirectDerivations); if (rs->Size() >= 1) return rs->GetElement(0); else return nullptr; } void mitk::DataStorage::PrintSelf(std::ostream &os, itk::Indent indent) const { // Superclass::PrintSelf(os, indent); DataStorage::SetOfObjects::ConstPointer all = this->GetAll(); os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl; for (DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++) { std::string name; allIt.Value()->GetName(name); std::string datatype; if (allIt.Value()->GetData() != nullptr) datatype = allIt.Value()->GetData()->GetNameOfClass(); os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl; DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value()); if (parents->Size() > 0) { os << indent << " Direct sources: "; for (DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End(); parentIt++) os << parentIt.Value().GetPointer() << ", "; os << std::endl; } DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value()); if (derivations->Size() > 0) { os << indent << " Direct derivations: "; for (DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin(); derivationIt != derivations->End(); derivationIt++) os << derivationIt.Value().GetPointer() << ", "; os << std::endl; } } os << std::endl; } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::FilterSetOfObjects(const SetOfObjects *set, const NodePredicateBase *condition) const { if (set == nullptr) return nullptr; DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); for (DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++) if (condition == nullptr || condition->CheckNode(it.Value()) == true) // alway copy the set, otherwise the iterator in DataStorage::Remove() will crash result->InsertElement(result->Size(), it.Value()); return DataStorage::SetOfObjects::ConstPointer(result); } const mitk::DataNode::GroupTagList mitk::DataStorage::GetGroupTags() const { DataNode::GroupTagList result; SetOfObjects::ConstPointer all = this->GetAll(); if (all.IsNull()) return result; for (DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End(); nodeIt++) // for each node { PropertyList *pl = nodeIt.Value()->GetPropertyList(); for (auto propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end(); ++propIt) if (dynamic_cast(propIt->second.GetPointer()) != nullptr) result.insert(propIt->first); } return result; } void mitk::DataStorage::EmitAddNodeEvent(const DataNode *node) { AddNodeEvent.Send(node); } void mitk::DataStorage::EmitRemoveNodeEvent(const DataNode *node) { RemoveNodeEvent.Send(node); } void mitk::DataStorage::OnNodeInteractorChanged(itk::Object *caller, const itk::EventObject &) { const auto *_Node = dynamic_cast(caller); if (_Node) { InteractorChangedNodeEvent.Send(_Node); } } void mitk::DataStorage::OnNodeModifiedOrDeleted(const itk::Object *caller, const itk::EventObject &event) { if (m_BlockNodeModifiedEvents) return; const auto *_Node = dynamic_cast(caller); if (_Node) { const auto *modEvent = dynamic_cast(&event); if (modEvent) ChangedNodeEvent.Send(_Node); else DeleteNodeEvent.Send(_Node); } } void mitk::DataStorage::AddListeners(const DataNode *_Node) { itk::MutexLockHolder locked(m_MutexOne); // node must not be 0 and must not be yet registered auto *NonConstNode = const_cast(_Node); if (_Node && m_NodeModifiedObserverTags.find(NonConstNode) == m_NodeModifiedObserverTags.end()) { itk::MemberCommand::Pointer nodeModifiedCommand = itk::MemberCommand::New(); nodeModifiedCommand->SetCallbackFunction(this, &DataStorage::OnNodeModifiedOrDeleted); m_NodeModifiedObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand); itk::MemberCommand::Pointer interactorChangedCommand = itk::MemberCommand::New(); interactorChangedCommand->SetCallbackFunction(this, &DataStorage::OnNodeInteractorChanged); m_NodeInteractorChangedObserverTags[NonConstNode] = NonConstNode->AddObserver(DataNode::InteractorChangedEvent(), interactorChangedCommand); // add itk delete listener on datastorage itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &DataStorage::OnNodeModifiedOrDeleted); // add observer m_NodeDeleteObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::DeleteEvent(), deleteCommand); } } void mitk::DataStorage::RemoveListeners(const DataNode *_Node) { itk::MutexLockHolder locked(m_MutexOne); // node must not be 0 and must be registered auto *NonConstNode = const_cast(_Node); if (_Node && m_NodeModifiedObserverTags.find(NonConstNode) != m_NodeModifiedObserverTags.end()) { // const cast is bad! but sometimes it is necessary. removing an observer does not really // touch the internal state NonConstNode->RemoveObserver(m_NodeModifiedObserverTags.find(NonConstNode)->second); NonConstNode->RemoveObserver(m_NodeDeleteObserverTags.find(NonConstNode)->second); NonConstNode->RemoveObserver(m_NodeInteractorChangedObserverTags.find(NonConstNode)->second); m_NodeModifiedObserverTags.erase(NonConstNode); m_NodeDeleteObserverTags.erase(NonConstNode); m_NodeInteractorChangedObserverTags.erase(NonConstNode); } } mitk::TimeGeometry::ConstPointer mitk::DataStorage::ComputeBoundingGeometry3D(const SetOfObjects *input, const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) const { if (input == nullptr) throw std::invalid_argument("DataStorage: input is invalid"); BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid = 0; Point3D point; Vector3D minSpacing; minSpacing.Fill(itk::NumericTraits::max()); ScalarType stmax = itk::NumericTraits::max(); ScalarType stmin = itk::NumericTraits::NonpositiveMin(); std::set existingTimePoints; ScalarType maximalTime = 0; // Needed for check of zero bounding boxes ScalarType nullpoint[] = {0, 0, 0, 0, 0, 0}; BoundingBox::BoundsArrayType itkBoundsZero(nullpoint); for (SetOfObjects::ConstIterator it = input->Begin(); it != input->End(); ++it) { DataNode::Pointer node = it->Value(); if ((node.IsNotNull()) && (node->GetData() != nullptr) && (node->GetData()->IsEmpty() == false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer)) { const TimeGeometry *timeGeometry = node->GetData()->GetUpdatedTimeGeometry(); if (timeGeometry != nullptr) { // bounding box (only if non-zero) BoundingBox::BoundsArrayType itkBounds = timeGeometry->GetBoundingBoxInWorld()->GetBounds(); if (itkBounds == itkBoundsZero) { continue; } unsigned char i; for (i = 0; i < 8; ++i) { point = timeGeometry->GetCornerPointInWorld(i); if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < large) pointscontainer->InsertElement(pointid++, point); else { itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. Node: " << node); } } try { // time bounds // iterate over all time steps // Attention: Objects with zero bounding box are not respected in time bound calculation for (TimeStepType i = 0; i < timeGeometry->CountTimeSteps(); i++) { // We must not use 'node->GetData()->GetGeometry(i)->GetSpacing()' here, as it returns the spacing // in its original space, which, in case of an image geometry, can have the values in different // order than in world space. For the further calculations, we need to have the spacing values // in world coordinate order (sag-cor-ax). Vector3D spacing; spacing.Fill(1.0); node->GetData()->GetGeometry(i)->IndexToWorld(spacing, spacing); for (int axis = 0; axis < 3; ++ axis) { ScalarType space = std::abs(spacing[axis]); if (space < minSpacing[axis]) { minSpacing[axis] = space; } } const auto curTimeBounds = timeGeometry->GetTimeBounds(i); if ((curTimeBounds[0] > stmin) && (curTimeBounds[0] < stmax)) { existingTimePoints.insert(curTimeBounds[0]); } if ((curTimeBounds[1] > maximalTime) && (curTimeBounds[1] < stmax)) { maximalTime = curTimeBounds[1]; } } } catch (itk::ExceptionObject &e) { MITK_ERROR << e << std::endl; } } } } BoundingBox::Pointer result = BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); // compute the number of time steps if (existingTimePoints.empty()) // make sure that there is at least one time sliced geometry in the data storage { existingTimePoints.insert(0.0); maximalTime = 1.0; } ArbitraryTimeGeometry::Pointer timeGeometry = nullptr; if (result->GetPoints()->Size() > 0) { // Initialize a geometry of a single time step Geometry3D::Pointer geometry = Geometry3D::New(); geometry->Initialize(); // correct bounding-box (is now in mm, should be in index-coordinates) // according to spacing BoundingBox::BoundsArrayType bounds = result->GetBounds(); AffineTransform3D::OutputVectorType offset; for (int i = 0; i < 3; ++i) { offset[i] = bounds[i * 2]; bounds[i * 2] = 0.0; bounds[i * 2 + 1] = (bounds[i * 2 + 1] - offset[i]) / minSpacing[i]; } geometry->GetIndexToWorldTransform()->SetOffset(offset); geometry->SetBounds(bounds); geometry->SetSpacing(minSpacing); // Initialize the time sliced geometry auto tsIterator = existingTimePoints.cbegin(); auto tsPredecessor = tsIterator++; auto tsEnd = existingTimePoints.cend(); timeGeometry = ArbitraryTimeGeometry::New(); for (; tsIterator != tsEnd; ++tsIterator, ++tsPredecessor) { timeGeometry->AppendNewTimeStep(geometry, *tsPredecessor, *tsIterator); } timeGeometry->AppendNewTimeStep(geometry, *tsPredecessor, maximalTime); timeGeometry->Update(); } return timeGeometry.GetPointer(); } mitk::TimeGeometry::ConstPointer mitk::DataStorage::ComputeBoundingGeometry3D(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) const { return this->ComputeBoundingGeometry3D(this->GetAll(), boolPropertyKey, renderer, boolPropertyKey2); } mitk::TimeGeometry::ConstPointer mitk::DataStorage::ComputeVisibleBoundingGeometry3D(const BaseRenderer *renderer, const char *boolPropertyKey) { return ComputeBoundingGeometry3D("visible", renderer, boolPropertyKey); } mitk::BoundingBox::Pointer mitk::DataStorage::ComputeBoundingBox(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) { BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid = 0; Point3D point; // Needed for check of zero bounding boxes ScalarType nullpoint[] = {0, 0, 0, 0, 0, 0}; BoundingBox::BoundsArrayType itkBoundsZero(nullpoint); SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if ((node.IsNotNull()) && (node->GetData() != nullptr) && (node->GetData()->IsEmpty() == false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer)) { const TimeGeometry *geometry = node->GetData()->GetUpdatedTimeGeometry(); if (geometry != nullptr) { // bounding box (only if non-zero) BoundingBox::BoundsArrayType itkBounds = geometry->GetBoundingBoxInWorld()->GetBounds(); if (itkBounds == itkBoundsZero) { continue; } unsigned char i; for (i = 0; i < 8; ++i) { point = geometry->GetCornerPointInWorld(i); if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < large) pointscontainer->InsertElement(pointid++, point); else { itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. Node: " << node); } } } } } BoundingBox::Pointer result = BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); return result; } mitk::TimeBounds mitk::DataStorage::ComputeTimeBounds(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) { TimeBounds timeBounds; ScalarType stmin, stmax, cur; stmin = itk::NumericTraits::NonpositiveMin(); stmax = itk::NumericTraits::max(); timeBounds[0] = stmax; timeBounds[1] = stmin; SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if ((node.IsNotNull()) && (node->GetData() != nullptr) && (node->GetData()->IsEmpty() == false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer)) { const TimeGeometry *geometry = node->GetData()->GetUpdatedTimeGeometry(); if (geometry != nullptr) { const TimeBounds &curTimeBounds = geometry->GetTimeBounds(); cur = curTimeBounds[0]; // is it after -infinity, but before everything else that we found until now? if ((cur > stmin) && (cur < timeBounds[0])) timeBounds[0] = cur; cur = curTimeBounds[1]; // is it before infinity, but after everything else that we found until now? if ((cur < stmax) && (cur > timeBounds[1])) timeBounds[1] = cur; } } } if (!(timeBounds[0] < stmax)) { timeBounds[0] = stmin; timeBounds[1] = stmax; } return timeBounds; } void mitk::DataStorage::BlockNodeModifiedEvents(bool block) { m_BlockNodeModifiedEvents = block; } -mitk::DataNode::Pointer mitk::FindTopmostVisibleNode(const DataStorage::SetOfObjects* nodes, - const Point3D worldposition, +mitk::DataNode::Pointer mitk::FindTopmostVisibleNode(const DataStorage::SetOfObjects::ConstPointer nodes, + const Point3D worldPosition, const TimePointType timePoint, const BaseRenderer* baseRender) { - DataNode::Pointer topLayerNode; - - if (nullptr == nodes) + if (nodes.IsNull()) + { return nullptr; + } + mitk::DataNode::Pointer topLayerNode = nullptr; int maxLayer = std::numeric_limits::min(); for (auto node : *nodes) { if (node.IsNull()) + { continue; + } bool isHelperObject = false; node->GetBoolProperty("helper object", isHelperObject); - if (isHelperObject) + { continue; + } auto data = node->GetData(); - if (nullptr == data) + { continue; + } auto geometry = data->GetGeometry(); - - if (nullptr == geometry || !geometry->IsInside(worldposition)) + if (nullptr == geometry || !geometry->IsInside(worldPosition)) + { continue; + } auto timeGeometry = data->GetUpdatedTimeGeometry(); - - if (timeGeometry == nullptr) + if (nullptr == timeGeometry) + { continue; + } if (!timeGeometry->IsValidTimePoint(timePoint)) + { continue; + } int layer = 0; - - if (!node->GetIntProperty("layer", layer)) + if (!node->GetIntProperty("layer", layer, baseRender)) + { continue; + } if (layer <= maxLayer) + { continue; + } if (!node->IsVisible(baseRender)) + { continue; + } topLayerNode = node; maxLayer = layer; } return topLayerNode; } diff --git a/Modules/Core/src/DataManagement/mitkLookupTable.cpp b/Modules/Core/src/DataManagement/mitkLookupTable.cpp index c6a61fcb8c..88cd6becd8 100644 --- a/Modules/Core/src/DataManagement/mitkLookupTable.cpp +++ b/Modules/Core/src/DataManagement/mitkLookupTable.cpp @@ -1,643 +1,643 @@ /*=================================================================== 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 "mitkLookupTable.h" #include #include #include #include #include #include #include #include #include #include #include #include #include -const char *const mitk::LookupTable::typenameList[] = { +std::vector mitk::LookupTable::typenameList = { "Grayscale", "Inverse Grayscale", "Hot Iron", "Jet", "Jet Transparent", "Plasma", "Inferno", "Viridis", "Magma", "Legacy Binary", "Legacy Rainbow Color", "Multilabel", "PET Color", - "PET 20", - "END_OF_ARRAY" // Do not add typenames after this entry (see QmitkDataManagerView::ColormapMenuAboutToShow()) + "PET 20" }; -mitk::LookupTable::LookupTable() : m_Window(0.0), m_Level(0.0), m_Opacity(1.0), m_type(mitk::LookupTable::GRAYSCALE) +mitk::LookupTable::LookupTable() : m_Window(0.0), m_Level(0.0), m_Opacity(1.0), m_Type(mitk::LookupTable::GRAYSCALE) { m_LookupTable = vtkSmartPointer::New(); this->BuildGrayScaleLookupTable(); } mitk::LookupTable::LookupTable(const LookupTable &other) : itk::DataObject(), m_LookupTable(vtkSmartPointer::New()) { m_LookupTable->DeepCopy(other.m_LookupTable); } mitk::LookupTable::~LookupTable() { } void mitk::LookupTable::SetVtkLookupTable(vtkSmartPointer lut) { if ((!lut) || (m_LookupTable == lut)) { return; } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::SetType(const mitk::LookupTable::LookupTableType type) { - if (m_type == type) + if (m_Type == type) return; switch (type) { case (mitk::LookupTable::GRAYSCALE): this->BuildGrayScaleLookupTable(); break; case (mitk::LookupTable::INVERSE_GRAYSCALE): this->BuildInverseGrayScaleLookupTable(); break; case (mitk::LookupTable::HOT_IRON): this->BuildHotIronLookupTable(); break; case (mitk::LookupTable::JET): this->BuildJetLookupTable(); break; case (mitk::LookupTable::JET_TRANSPARENT): this->BuildJetLookupTable(true); break; case (mitk::LookupTable::PLASMA): this->BuildPlasmaLookupTable(); break; case (mitk::LookupTable::INFERNO): this->BuildInfernoLookupTable(); break; case (mitk::LookupTable::VIRIDIS): this->BuildViridisLookupTable(); break; case (mitk::LookupTable::MAGMA): this->BuildMagmaLookupTable(); break; case (mitk::LookupTable::LEGACY_BINARY): this->BuildLegacyBinaryLookupTable(); break; case (mitk::LookupTable::MULTILABEL): this->BuildMultiLabelLookupTable(); break; case (mitk::LookupTable::PET_COLOR): this->BuildPETColorLookupTable(); break; case (mitk::LookupTable::PET_20): this->BuildPET20LookupTable(); break; case (mitk::LookupTable::LEGACY_RAINBOW_COLOR): this->BuildLegacyRainbowColorLookupTable(); break; default: MITK_ERROR << "non-existing colormap"; return; } - m_type = type; + m_Type = type; } void mitk::LookupTable::SetType(const std::string &typeName) { - int i = 0; - std::string lutType = this->typenameList[i]; - - while (lutType != "END_OF_ARRAY") + for (size_t i = 0; i < typenameList.size(); ++i) { - if (lutType == typeName) + if (typenameList.at(i) == typeName) { this->SetType(static_cast(i)); } - lutType = this->typenameList[++i]; } } mitk::LookupTable::LookupTableType mitk::LookupTable::GetActiveType() const { - return m_type; + return m_Type; } std::string mitk::LookupTable::GetActiveTypeAsString() const { - return std::string(typenameList[(int)m_type]); + if (static_cast(m_Type) < typenameList.size()) + { + return typenameList.at(m_Type); + } + + return ""; } void mitk::LookupTable::ChangeOpacityForAll(float opacity) { int noValues = m_LookupTable->GetNumberOfTableValues(); double rgba[4]; for (int i = 0; i < noValues; i++) { m_LookupTable->GetTableValue(i, rgba); rgba[3] = opacity; m_LookupTable->SetTableValue(i, rgba); } this->Modified(); // need to call modified, since LookupTableProperty seems to be unchanged so no widget-update is // executed } void mitk::LookupTable::ChangeOpacity(int index, float opacity) { int noValues = m_LookupTable->GetNumberOfTableValues(); if (index > noValues) { MITK_INFO << "could not change opacity. index exceed size of lut ... " << std::endl; return; } double rgba[4]; m_LookupTable->GetTableValue(index, rgba); rgba[3] = opacity; m_LookupTable->SetTableValue(index, rgba); this->Modified(); // need to call modified, since LookupTableProperty seems to be unchanged so no widget-update is // executed } void mitk::LookupTable::GetColor(double value, double rgb[3]) { this->GetVtkLookupTable()->GetColor(value, rgb); } void mitk::LookupTable::GetTableValue(int index, double rgba[4]) { this->GetVtkLookupTable()->GetTableValue(index, rgba); } void mitk::LookupTable::SetTableValue(int index, double rgba[4]) { this->GetVtkLookupTable()->SetTableValue(index, rgba); } vtkSmartPointer mitk::LookupTable::GetVtkLookupTable() const { return m_LookupTable; } mitk::LookupTable::RawLookupTableType *mitk::LookupTable::GetRawLookupTable() const { return m_LookupTable->GetPointer(0); } bool mitk::LookupTable::operator==(const mitk::LookupTable &other) const { if (m_LookupTable == other.GetVtkLookupTable()) return true; vtkLookupTable *olut = other.GetVtkLookupTable(); if (olut == nullptr) return false; bool equal = (m_LookupTable->GetNumberOfColors() == olut->GetNumberOfColors()) && (m_LookupTable->GetTableRange()[0] == olut->GetTableRange()[0]) && (m_LookupTable->GetTableRange()[1] == olut->GetTableRange()[1]) && (m_LookupTable->GetHueRange()[0] == olut->GetHueRange()[0]) && (m_LookupTable->GetHueRange()[1] == olut->GetHueRange()[1]) && (m_LookupTable->GetSaturationRange()[0] == olut->GetSaturationRange()[0]) && (m_LookupTable->GetSaturationRange()[1] == olut->GetSaturationRange()[1]) && (m_LookupTable->GetValueRange()[0] == olut->GetValueRange()[0]) && (m_LookupTable->GetValueRange()[1] == olut->GetValueRange()[1]) && (m_LookupTable->GetAlphaRange()[0] == olut->GetAlphaRange()[0]) && (m_LookupTable->GetAlphaRange()[1] == olut->GetAlphaRange()[1]) && (m_LookupTable->GetRamp() == olut->GetRamp()) && (m_LookupTable->GetScale() == olut->GetScale()) && (m_LookupTable->GetAlpha() == olut->GetAlpha()) && (m_LookupTable->GetTable()->GetNumberOfTuples() == olut->GetTable()->GetNumberOfTuples()); if (equal == false) return false; for (vtkIdType i = 0; i < m_LookupTable->GetNumberOfTableValues(); i++) { bool tvequal = (m_LookupTable->GetTableValue(i)[0] == olut->GetTableValue(i)[0]) && (m_LookupTable->GetTableValue(i)[1] == olut->GetTableValue(i)[1]) && (m_LookupTable->GetTableValue(i)[2] == olut->GetTableValue(i)[2]) && (m_LookupTable->GetTableValue(i)[3] == olut->GetTableValue(i)[3]); if (tvequal == false) return false; } return true; } bool mitk::LookupTable::operator!=(const mitk::LookupTable &other) const { return !(*this == other); } mitk::LookupTable &mitk::LookupTable::operator=(const mitk::LookupTable &LookupTable) { if (this == &LookupTable) { return *this; } else { m_LookupTable = LookupTable.GetVtkLookupTable(); return *this; } } void mitk::LookupTable::UpdateOutputInformation() { if (this->GetSource()) { this->GetSource()->UpdateOutputInformation(); } } void mitk::LookupTable::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::LookupTable::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::LookupTable::VerifyRequestedRegion() { // normally we should check if the requested region lies within the // largest possible region. Since for lookup-tables we assume, that the // requested region is always the largest possible region, we can always // return true! return true; } void mitk::LookupTable::SetRequestedRegion(const itk::DataObject *) { // not implemented, since we always want to have the RequestedRegion // to be set to LargestPossibleRegion } vtkSmartPointer mitk::LookupTable::CreateColorTransferFunction() { vtkSmartPointer colorFunction = vtkSmartPointer::New(); mitk::LookupTable::RawLookupTableType *rawLookupTable = this->GetRawLookupTable(); int num_of_values = m_LookupTable->GetNumberOfTableValues(); auto cols = new double[3 * num_of_values]; double *colsHead = cols; for (int i = 0; i < num_of_values; ++i) { *cols = static_cast(*rawLookupTable) / 255.0; ++cols; ++rawLookupTable; *cols = static_cast(*rawLookupTable) / 255.0; ++cols; ++rawLookupTable; *cols = static_cast(*rawLookupTable) / 255.0; ++cols; ++rawLookupTable; ++rawLookupTable; } colorFunction->BuildFunctionFromTable( m_LookupTable->GetTableRange()[0], m_LookupTable->GetTableRange()[1], num_of_values, colsHead); return colorFunction; } void mitk::LookupTable::CreateColorTransferFunction(vtkColorTransferFunction *&colorFunction) { colorFunction = this->CreateColorTransferFunction(); } vtkSmartPointer mitk::LookupTable::CreateOpacityTransferFunction() { vtkSmartPointer opacityFunction = vtkSmartPointer::New(); mitk::LookupTable::RawLookupTableType *rgba = this->GetRawLookupTable(); int num_of_values = m_LookupTable->GetNumberOfTableValues(); auto alphas = new double[num_of_values]; double *alphasHead = alphas; rgba += 3; for (int i = 0; i < num_of_values; ++i) { *alphas = static_cast(*rgba) / 255.0; ++alphas; rgba += 4; } opacityFunction->BuildFunctionFromTable( m_LookupTable->GetTableRange()[0], m_LookupTable->GetTableRange()[1], num_of_values, alphasHead); return opacityFunction; } void mitk::LookupTable::CreateOpacityTransferFunction(vtkPiecewiseFunction *&opacityFunction) { opacityFunction = this->CreateOpacityTransferFunction(); } vtkSmartPointer mitk::LookupTable::CreateGradientTransferFunction() { vtkSmartPointer gradientFunction = vtkSmartPointer::New(); mitk::LookupTable::RawLookupTableType *rgba = this->GetRawLookupTable(); int num_of_values = m_LookupTable->GetNumberOfTableValues(); auto alphas = new double[num_of_values]; double *alphasHead = alphas; rgba += 3; for (int i = 0; i < num_of_values; ++i) { *alphas = static_cast(*rgba) / 255.0; ++alphas; rgba += 4; } gradientFunction->BuildFunctionFromTable( m_LookupTable->GetTableRange()[0], m_LookupTable->GetTableRange()[1], num_of_values, alphasHead); return gradientFunction; } void mitk::LookupTable::CreateGradientTransferFunction(vtkPiecewiseFunction *&gradientFunction) { gradientFunction = this->CreateGradientTransferFunction(); } void mitk::LookupTable::PrintSelf(std::ostream &os, itk::Indent indent) const { os << indent; m_LookupTable->PrintHeader(os, vtkIndent()); } itk::LightObject::Pointer mitk::LookupTable::InternalClone() const { itk::LightObject::Pointer result(new Self(*this)); result->UnRegister(); return result; } void mitk::LookupTable::BuildGrayScaleLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetRampToLinear(); lut->SetSaturationRange(0.0, 0.0); lut->SetHueRange(0.0, 0.0); lut->SetValueRange(0.0, 1.0); lut->Build(); m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildLegacyBinaryLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetRampToLinear(); lut->SetSaturationRange(0.0, 0.0); lut->SetHueRange(0.0, 0.0); lut->SetValueRange(0.0, 1.0); lut->Build(); lut->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildInverseGrayScaleLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetTableRange(0, 1); lut->SetSaturationRange(0, 0); lut->SetHueRange(0, 0); lut->SetValueRange(1, 0); lut->SetAlphaRange(1, 0); lut->Build(); m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildHotIronLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue( i, (double)HotIron[i][0] / 255.0, (double)HotIron[i][1] / 255.0, (double)HotIron[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildJetLookupTable(bool transparent) { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->Build(); int i = 0; if (transparent) { // Lowest intensity is transparent lut->SetTableValue(0, (double)Jet[0][0] / 255.0, (double)Jet[0][1] / 255.0, (double)Jet[0][2] / 255.0, 0.0); i = 1; } for (; i < 256; i++) { lut->SetTableValue(i, (double)Jet[i][0] / 255.0, (double)Jet[i][1] / 255.0, (double)Jet[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildPETColorLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->SetTableRange((m_Level - m_Window / 2.0), (m_Level + m_Window / 2.0)); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue( i, (double)PETColor[i][0] / 255.0, (double)PETColor[i][1] / 255.0, (double)PETColor[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildPET20LookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->SetTableRange((m_Level - m_Window / 2.0), (m_Level + m_Window / 2.0)); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue(i, (double)PET20[i][0] / 255.0, (double)PET20[i][1] / 255.0, (double)PET20[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildMultiLabelLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(65536); lut->SetTableRange(0, 65536); lut->Build(); lut->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); // background for (int i = 0; i < 25; i++) { lut->SetTableValue(i+1, Multilabel[i][0], Multilabel[i][1], Multilabel[i][2], 0.4); } for (int i = 26; i < 65536; i++) { if (i % 12 == 0) lut->SetTableValue(i, 1.0, 0.0, 0.0, 0.4); else if (i % 12 == 1) lut->SetTableValue(i, 0.0, 1.0, 0.0, 0.4); else if (i % 12 == 2) lut->SetTableValue(i, 0.0, 0.0, 1.0, 0.4); else if (i % 12 == 3) lut->SetTableValue(i, 1.0, 1.0, 0.0, 0.4); else if (i % 12 == 4) lut->SetTableValue(i, 0.0, 1.0, 1.0, 0.4); else if (i % 12 == 5) lut->SetTableValue(i, 1.0, 0.0, 1.0, 0.4); else if (i % 12 == 6) lut->SetTableValue(i, 1.0, 0.5, 0.0, 0.4); else if (i % 12 == 7) lut->SetTableValue(i, 0.0, 1.0, 0.5, 0.4); else if (i % 12 == 8) lut->SetTableValue(i, 0.5, 0.0, 1.0, 0.4); else if (i % 12 == 9) lut->SetTableValue(i, 1.0, 1.0, 0.5, 0.4); else if (i % 12 == 10) lut->SetTableValue(i, 0.5, 1.0, 1.0, 0.4); else if (i % 12 == 11) lut->SetTableValue(i, 1.0, 0.5, 1.0, 0.4); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildLegacyRainbowColorLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetRampToLinear(); lut->SetHueRange(0.6667, 0.0); lut->SetTableRange(0.0, 20.0); lut->Build(); m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildPlasmaLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue( i, (double)Plasma[i][0] / 255.0, (double)Plasma[i][1] / 255.0, (double)Plasma[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildInfernoLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue( i, (double)Inferno[i][0] / 255.0, (double)Inferno[i][1] / 255.0, (double)Inferno[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildViridisLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue( i, (double)Viridis[i][0] / 255.0, (double)Viridis[i][1] / 255.0, (double)Viridis[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } void mitk::LookupTable::BuildMagmaLookupTable() { vtkSmartPointer lut = vtkSmartPointer::New(); lut->SetNumberOfTableValues(256); lut->Build(); for (int i = 0; i < 256; i++) { lut->SetTableValue( i, (double)Magma[i][0] / 255.0, (double)Magma[i][1] / 255.0, (double)Magma[i][2] / 255.0, 1.0); } m_LookupTable = lut; this->Modified(); } diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp new file mode 100644 index 0000000000..925f7bf984 --- /dev/null +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp @@ -0,0 +1,787 @@ +/*=================================================================== + + The Medical Imaging Interaction Toolkit (MITK) + + Copyright (c) German Cancer Research Center, + Division of Medical Image Computing. + All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. + + See LICENSE.txt or http://www.mitk.org for details. + + ===================================================================*/ + +#include "mitkDisplayActionEventBroadcast.h" + + // us +#include "usGetModuleContext.h" +#include "usModuleContext.h" + +// mitk core module +#include "mitkCompositePixelValueToString.h" +#include "mitkDisplayActionEvents.h" +#include "mitkImage.h" +#include "mitkImagePixelReadAccessor.h" +#include "mitkInteractionPositionEvent.h" +#include "mitkLine.h" +#include "mitkNodePredicateDataType.h" +#include "mitkPixelTypeMultiplex.h" +#include "mitkStatusBar.h" + +mitk::DisplayActionEventBroadcast::DisplayActionEventBroadcast() + : m_AlwaysReact(false) + , m_AutoRepeat(false) + , m_IndexToSliceModifier(4) + , m_InvertScrollDirection(false) + , m_InvertZoomDirection(false) + , m_ZoomFactor(2) + , m_InvertMoveDirection(false) + , m_InvertLevelWindowDirection(false) + , m_LinkPlanes(true) +{ + m_StartCoordinateInMM.Fill(0); + m_LastDisplayCoordinate.Fill(0); + m_LastCoordinateInMM.Fill(0); + m_CurrentDisplayCoordinate.Fill(0); + + // register the broadcast class (itself) as an interaction event observer via micro services + us::ServiceProperties props; + props["name"] = std::string("DisplayActionEventBroadcast"); + m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); +} + +mitk::DisplayActionEventBroadcast::~DisplayActionEventBroadcast() +{ + m_ServiceRegistration.Unregister(); +} + +void mitk::DisplayActionEventBroadcast::Notify(InteractionEvent* interactionEvent, bool isHandled) +{ + // the event is passed to the state machine interface to be handled + if (!isHandled || m_AlwaysReact) + { + HandleEvent(interactionEvent, nullptr); + } +} + +void mitk::DisplayActionEventBroadcast::ConnectActionsAndFunctions() +{ + CONNECT_CONDITION("check_position_event", CheckPositionEvent); + CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); + CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); + + CONNECT_FUNCTION("init", Init); + CONNECT_FUNCTION("move", Move); + CONNECT_FUNCTION("zoom", Zoom); + CONNECT_FUNCTION("scroll", Scroll); + CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); + CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); + CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); + CONNECT_FUNCTION("setCrosshair", SetCrosshair); + + CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) + + CONNECT_FUNCTION("startRotation", StartRotation); + CONNECT_FUNCTION("endRotation", EndRotation); + CONNECT_FUNCTION("rotate", Rotate); + + CONNECT_FUNCTION("swivel", Swivel); +} + +void mitk::DisplayActionEventBroadcast::ConfigurationChanged() +{ + PropertyList::Pointer properties = GetAttributes(); + + // allwaysReact + std::string strAlwaysReact = ""; + m_AlwaysReact = false; + if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) + { + if (strAlwaysReact == "true") + { + m_AlwaysReact = true; + } + } + + // auto repeat + std::string strAutoRepeat = ""; + m_AutoRepeat = false; + if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) + { + if (strAutoRepeat == "true") + { + m_AutoRepeat = true; + } + } + + // pixel movement for scrolling one slice + std::string strPixelPerSlice = ""; + m_IndexToSliceModifier = 4; + if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) + { + m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); + } + + // scroll direction + if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) + { + m_ScrollDirection = "updown"; + } + + m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); + + // zoom direction + if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) + { + m_ZoomDirection = "updown"; + } + + m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); + m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); + + if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) + { + m_LevelDirection = "leftright"; + } + + m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); + + // coupled rotation + std::string strCoupled = ""; + m_LinkPlanes = false; + if (properties->GetStringProperty("coupled", strCoupled)) + { + if (strCoupled == "true") + { + m_LinkPlanes = true; + } + } + + // zoom factor + std::string strZoomFactor = ""; + properties->GetStringProperty("zoomFactor", strZoomFactor); + m_ZoomFactor = .05; + if (atoi(strZoomFactor.c_str()) > 0) + { + m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); + } +} + +bool mitk::DisplayActionEventBroadcast::FilterEvents(InteractionEvent* interactionEvent, DataNode * /*dataNode*/) +{ + BaseRenderer* sendingRenderer = interactionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return false; + } + + if (BaseRenderer::Standard3D == sendingRenderer->GetMapperID()) + { + return false; + } + + return true; +} + +bool mitk::DisplayActionEventBroadcast::CheckPositionEvent(const InteractionEvent *interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return false; + } + + return true; +} + +bool mitk::DisplayActionEventBroadcast::CheckRotationPossible(const InteractionEvent *interactionEvent) +{ + // Decide between moving and rotation slices. + /* + Detailed logic: + + 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be + rotated. Needs not even be counted or checked. + 2. Inspect every other SliceNavigationController + - calculate the line intersection of this SliceNavigationController's plane with our rendering plane + - if there is NO interesection, ignore and continue + - IF there is an intersection + - check the mouse cursor's distance from that line. + 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in + "locked" mode) + 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate + 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to + rotate + - if yes, we just push this line to the "other" lines and rotate it along + - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to + rotate + */ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return false; + } + + BaseRenderer* clickedRenderer = positionEvent->GetSender(); + const PlaneGeometry* ourViewportGeometry = clickedRenderer->GetCurrentWorldPlaneGeometry(); + + if (nullptr == ourViewportGeometry) + { + return false; + } + + Point3D cursorPosition = positionEvent->GetPositionInWorld(); + const auto spacing = ourViewportGeometry->GetSpacing(); + const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor + const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) + Line3D intersectionLineWithGeometryToBeRotated; + + bool hitMultipleLines(false); + m_SNCsToBeRotated.clear(); + + const double threshholdDistancePixels = 12.0; + + auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); + + for (auto renWin : renWindows) + { + SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); + + // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. + if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) + continue; + + const PlaneGeometry *otherRenderersRenderPlane = snc->GetCurrentPlaneGeometry(); + if (nullptr == otherRenderersRenderPlane) + { + continue; // ignore, we don't see a plane + } + + // check if there is an intersection + Line3D intersectionLine; // between rendered/clicked geometry and the one being analyzed + if (!ourViewportGeometry->IntersectionLine(otherRenderersRenderPlane, intersectionLine)) + { + continue; // we ignore this plane, it's parallel to our plane + } + + // check distance from intersection line + const double distanceFromIntersectionLine = intersectionLine.Distance(cursorPosition) / spacing[snc->GetDefaultViewDirection()]; + + // far away line, only remember for linked rotation if necessary + if (distanceFromIntersectionLine > threshholdDistancePixels) + { + anyOtherGeometry = otherRenderersRenderPlane; // we just take the last one, so overwrite each iteration (we just + // need some crossing point) + // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used + if (m_LinkPlanes) + { + m_SNCsToBeRotated.push_back(snc); + } + } + else // close to cursor + { + if (nullptr == geometryToBeRotated) // first one close to the cursor + { + geometryToBeRotated = otherRenderersRenderPlane; + intersectionLineWithGeometryToBeRotated = intersectionLine; + m_SNCsToBeRotated.push_back(snc); + } + else + { + // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane + // together with the primary one + // if different, DON'T rotate + if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && + intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < eps) + { + m_SNCsToBeRotated.push_back(snc); + } + else + { + hitMultipleLines = true; + } + } + } + } + + bool moveSlices(true); + + if (geometryToBeRotated && anyOtherGeometry && ourViewportGeometry && !hitMultipleLines) + { + // assure all three are valid, so calculation of center of rotation can be done + moveSlices = false; + } + // question in state machine is: "rotate?" + if (moveSlices) // i.e. NOT rotate + { + return false; + } + else + { + // we DO have enough information for rotation + // remember where the last cursor position ON THE LINE has been observed + m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project(cursorPosition); + + // find center of rotation by intersection with any of the OTHER lines + if (anyOtherGeometry->IntersectionPoint(intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) + { + return true; + } + else + { + return false; + } + } + return false; +} + +bool mitk::DisplayActionEventBroadcast::CheckSwivelPossible(const InteractionEvent *interactionEvent) +{ + const ScalarType ThresholdDistancePixels = 6.0; + + // Decide between moving and rotation: if we're close to the crossing + // point of the planes, moving mode is entered, otherwise + // rotation/swivel mode + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return false; + } + + BaseRenderer *renderer = interactionEvent->GetSender(); + if (nullptr == renderer) + { + return false; + } + + const Point3D& cursor = positionEvent->GetPositionInWorld(); + + m_SNCsToBeRotated.clear(); + + const PlaneGeometry* clickedGeometry(nullptr); + const PlaneGeometry* otherGeometry1(nullptr); + const PlaneGeometry* otherGeometry2(nullptr); + + auto registeredRenderWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renWin : registeredRenderWindows) + { + SliceNavigationController* snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); + + // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. + if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) + continue; + + // unsigned int slice = (*iter)->GetSlice()->GetPos(); + // unsigned int time = (*iter)->GetTime()->GetPos(); + + const PlaneGeometry *planeGeometry = snc->GetCurrentPlaneGeometry(); + if (!planeGeometry) + continue; + + if (snc == renderer->GetSliceNavigationController()) + { + clickedGeometry = planeGeometry; + m_SNCsToBeRotated.push_back(snc); + } + else + { + if (otherGeometry1 == nullptr) + { + otherGeometry1 = planeGeometry; + } + else + { + otherGeometry2 = planeGeometry; + } + if (m_LinkPlanes) + { + // If planes are linked, apply rotation to all planes + m_SNCsToBeRotated.push_back(snc); + } + } + } + + Line3D line; + Point3D point; + if ((clickedGeometry != nullptr) && (otherGeometry1 != nullptr) && (otherGeometry2 != nullptr) && + clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) + { + m_CenterOfRotation = point; + if (m_CenterOfRotation.EuclideanDistanceTo(cursor) < ThresholdDistancePixels) + { + return false; + } + else + { + m_ReferenceCursor = positionEvent->GetPointerPositionOnScreen(); + + // Get main axes of rotation plane and store it for rotation step + m_RotationPlaneNormal = clickedGeometry->GetNormal(); + + ScalarType xVector[] = { 1.0, 0.0, 0.0 }; + ScalarType yVector[] = { 0.0, 1.0, 0.0 }; + clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); + clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); + + m_RotationPlaneNormal.Normalize(); + m_RotationPlaneXVector.Normalize(); + m_RotationPlaneYVector.Normalize(); + + m_PreviousRotationAxis.Fill(0.0); + m_PreviousRotationAxis[2] = 1.0; + m_PreviousRotationAngle = 0.0; + + return true; + } + } + else + { + return false; + } + return false; +} + +void mitk::DisplayActionEventBroadcast::Init(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; + positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); + m_LastCoordinateInMM = m_StartCoordinateInMM; +} + +void mitk::DisplayActionEventBroadcast::Move(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + BaseRenderer* sender = interactionEvent->GetSender(); + Vector2D moveVector = m_LastDisplayCoordinate - positionEvent->GetPointerPositionOnScreen(); + + if (m_InvertMoveDirection) + { + moveVector *= -1.0; + } + + moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); // #TODO: put here? + + // store new display coordinate + m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + + // propagate move event with computed geometry values + InvokeEvent(DisplayMoveEvent(interactionEvent, moveVector)); +} + +void mitk::DisplayActionEventBroadcast::SetCrosshair(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + Point3D position = positionEvent->GetPositionInWorld(); + + // propagate set crosshair event with computed geometry values + InvokeEvent(DisplaySetCrosshairEvent(interactionEvent, position)); +} + +void mitk::DisplayActionEventBroadcast::Zoom(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + float factor = 1.0; + float distance = 0; + + if (m_ZoomDirection == "updown") + { + distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; + } + else + { + distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; + } + + if (m_InvertZoomDirection) + { + distance *= -1.0; + } + + // set zooming speed + if (distance < 0.0) + { + factor = 1.0 / m_ZoomFactor; + } + else if (distance > 0.0) + { + factor = 1.0 * m_ZoomFactor; + } + + // store new display coordinates + m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; + m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + + // propagate zoom event with computed geometry values + InvokeEvent(DisplayZoomEvent(interactionEvent, factor, m_StartCoordinateInMM)); +} + +void mitk::DisplayActionEventBroadcast::Scroll(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + int sliceDelta = 0; + + // scroll direction + if (m_ScrollDirection == "updown") + { + sliceDelta = static_cast(m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]); + } + else + { + sliceDelta = static_cast(m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]); + } + + if (m_InvertScrollDirection) + { + sliceDelta *= -1; + } + + // set how many pixels the mouse has to be moved to scroll one slice + // if the mouse has been moved less than 'm_IndexToSliceModifier', pixels slice ONE slice only + if (sliceDelta > 0 && sliceDelta < m_IndexToSliceModifier) + { + sliceDelta = m_IndexToSliceModifier; + } + else if (sliceDelta < 0 && sliceDelta > -m_IndexToSliceModifier) + { + sliceDelta = -m_IndexToSliceModifier; + } + sliceDelta /= m_IndexToSliceModifier; + + // store new display coordinates + m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; + m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + + // propagate scroll event with computed geometry values + InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); +} + +void mitk::DisplayActionEventBroadcast::ScrollOneUp(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + int sliceDelta = 1; + if (m_InvertScrollDirection) + { + sliceDelta = -1; + } + + // propagate scroll event with a single slice delta (increase) + InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); +} + +void mitk::DisplayActionEventBroadcast::ScrollOneDown(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + int sliceDelta = -1; + if (m_InvertScrollDirection) + { + sliceDelta = 1; + } + + // propagate scroll event with a single slice delta (decrease) + InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); +} + +void mitk::DisplayActionEventBroadcast::AdjustLevelWindow(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + ScalarType level; + ScalarType window; + + if (m_LevelDirection == "leftright") + { + level = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; + window = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; + } + else + { + level = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; + window = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; + } + + if (m_InvertLevelWindowDirection) + { + level *= -1; + window *= -1; + } + + level *= static_cast(2); + window *= static_cast(2); + + // store new display coordinates + m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; + m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + + // propagate set level window event with the level and window delta + InvokeEvent(DisplaySetLevelWindowEvent(interactionEvent, level, window)); +} + +void mitk::DisplayActionEventBroadcast::StartRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) +{ + // nothing here; no event sent +} + +void mitk::DisplayActionEventBroadcast::EndRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) +{ + // nothing here; no event sent +} + +void mitk::DisplayActionEventBroadcast::Rotate(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) +{ + // nothing here; no event sent +} + +void mitk::DisplayActionEventBroadcast::Swivel(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) +{ + // nothing here; no event sent +} + +void mitk::DisplayActionEventBroadcast::UpdateStatusbar(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +{ + const auto* positionEvent = dynamic_cast(interactionEvent); + if (nullptr == positionEvent) + { + return; + } + + BaseRenderer::Pointer renderer = positionEvent->GetSender(); + + TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); + DataStorage::SetOfObjects::ConstPointer nodes = renderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); + if (nodes.IsNull()) + { + return; + } + + Point3D worldposition; + renderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); + auto globalCurrentTimePoint = renderer->GetTime(); + + Image::Pointer image3D; + DataNode::Pointer node; + DataNode::Pointer topSourceNode; + + int component = 0; + + node = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, renderer); + if (node.IsNull()) + { + return; + } + + bool isBinary(false); + node->GetBoolProperty("binary", isBinary); + if (isBinary) + { + DataStorage::SetOfObjects::ConstPointer sourcenodes = renderer->GetDataStorage()->GetSources(node, nullptr, true); + if (!sourcenodes->empty()) + { + topSourceNode = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, renderer); + } + if (topSourceNode.IsNotNull()) + { + image3D = dynamic_cast(topSourceNode->GetData()); + topSourceNode->GetIntProperty("Image.Displayed Component", component); + } + else + { + image3D = dynamic_cast(node->GetData()); + node->GetIntProperty("Image.Displayed Component", component); + } + } + else + { + image3D = dynamic_cast(node->GetData()); + node->GetIntProperty("Image.Displayed Component", component); + } + + // get the position and pixel value from the image and build up status bar text + auto statusBar = StatusBar::GetInstance(); + if (image3D.IsNotNull() && statusBar != nullptr) + { + itk::Index<3> p; + image3D->GetGeometry()->WorldToIndex(worldposition, p); + + auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); + if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) + { + std::string pixelValue = "Pixel RGB(A) value: "; + pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); + statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); + } + else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) + { + std::string pixelValue = "See ODF Details view. "; + statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); + } + else + { + ScalarType pixelValue; + mitkPixelTypeMultiplex5( + FastSinglePixelAccess, + image3D->GetChannelDescriptor().GetPixelType(), + image3D, + image3D->GetVolumeData(renderer->GetTimeStep()), + p, + pixelValue, + component); + statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue); + } + } + else + { + statusBar->DisplayImageInfoInvalid(); + } +} + +bool mitk::DisplayActionEventBroadcast::GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue) +{ + std::string valueAsString; + if (!propertyList->GetStringProperty(propertyName, valueAsString)) + { + return defaultValue; + } + else + { + if (valueAsString == "true") + { + return true; + } + else + { + return false; + } + } +} diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp new file mode 100644 index 0000000000..0b35416d73 --- /dev/null +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp @@ -0,0 +1,321 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkDisplayActionEventFunctions.h" + +// mitk core +#include "mitkBaseRenderer.h" +#include "mitkCameraController.h" +#include "mitkDisplayActionEvents.h" +#include "mitkInteractionPositionEvent.h" +#include "mitkLevelWindow.h" +#include "mitkLevelWindowProperty.h" +#include "mitkNodePredicateDataType.h" + +////////////////////////////////////////////////////////////////////////// +// STANDARD FUNCTIONS +////////////////////////////////////////////////////////////////////////// +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveSenderCameraAction() +{ + mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + sendingRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); + sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + BaseRenderer::GetInstance(sendingRenderer->GetRenderWindow())->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomSenderCameraAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + if (1.0 != displayActionEvent->GetZoomFactor()) + { + sendingRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); + sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + mitk::SliceNavigationController* sliceNavigationController = sendingRenderer->GetSliceNavigationController(); + if (nullptr == sliceNavigationController) + { + return; + } + if (sliceNavigationController->GetSliceLocked()) + { + return; + } + mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); + if (nullptr == sliceStepper) + { + return; + } + + // if only a single slice image was loaded, scrolling will affect the time steps + if (sliceStepper->GetSteps() <= 1) + { + sliceStepper = sliceNavigationController->GetTime(); + } + + sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetLevelWindowAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplaySetLevelWindowEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplaySetLevelWindowEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + // get the the topmost visible image of the sending renderer + DataStorage::Pointer storage = sendingRenderer->GetDataStorage(); + DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(NodePredicateDataType::New("Image")); + Point3D worldposition; + const auto* positionEvent = dynamic_cast(displayActionEvent->GetInteractionEvent()); + sendingRenderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); + auto globalCurrentTimePoint = sendingRenderer->GetTime(); + DataNode::Pointer node = FindTopmostVisibleNode(allImageNodes, worldposition, globalCurrentTimePoint, sendingRenderer); + if (node.IsNull()) + { + return; + } + + LevelWindow levelWindow = LevelWindow(); + node->GetLevelWindow(levelWindow); + ScalarType level = levelWindow.GetLevel(); + ScalarType window = levelWindow.GetWindow(); + + level += displayActionEvent->GetLevel(); + window += displayActionEvent->GetWindow(); + + levelWindow.SetLevelWindow(level, window); + auto* levelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); + if (nullptr != levelWindowProperty) + { + levelWindowProperty->SetLevelWindow(levelWindow); + sendingRenderer->GetRenderingManager()->RequestUpdateAll(); + } + } + }; + + return actionFunction; +} + +////////////////////////////////////////////////////////////////////////// +// SYNCHRONIZED FUNCTIONS +////////////////////////////////////////////////////////////////////////// +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction() +{ + mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); + currentRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); + currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); + } + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); + } + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + if (1.0 != displayActionEvent->GetZoomFactor()) + { + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); + currentRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); + currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); + } + } + } + } + }; + + return actionFunction; +} + +mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction() +{ + auto actionFunction = [](const itk::EventObject& displayInteractorEvent) + { + if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) + { + const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); + const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); + if (nullptr == sendingRenderer) + { + return; + } + + auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + for (auto renderWindow : allRenderWindows) + { + if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) + { + mitk::SliceNavigationController* sliceNavigationController = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); + if (nullptr == sliceNavigationController) + { + return; + } + if (sliceNavigationController->GetSliceLocked()) + { + return; + } + mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); + if (nullptr == sliceStepper) + { + return; + } + + // if only a single slice image was loaded, scrolling will affect the time steps + if (sliceStepper->GetSteps() <= 1) + { + sliceStepper = sliceNavigationController->GetTime(); + } + + sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); + } + } + } + }; + + return actionFunction; +} diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp new file mode 100644 index 0000000000..f28c3c6a99 --- /dev/null +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventHandler.cpp @@ -0,0 +1,75 @@ +/*=================================================================== + +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 "mitkDisplayActionEventHandler.h" + +void mitk::DisplayActionEventHandler::SetObservableBroadcast(DisplayActionEventBroadcast* observableBroadcast) +{ + if (m_ObservableBroadcast == observableBroadcast) + { + // no need to update the broadcast class + return; + } + + if (!m_ObservableBroadcast.IsExpired()) + { + auto observableBroadcastPtr = m_ObservableBroadcast.Lock(); + + // remove current observer + for (const auto& tag : m_ObserverTags) + { + observableBroadcastPtr->RemoveObserver(tag); + } + m_ObserverTags.clear(); + } + + // set new broadcast class + m_ObservableBroadcast = observableBroadcast; +} + +mitk::DisplayActionEventHandler::OberserverTagType mitk::DisplayActionEventHandler::ConnectDisplayActionEvent(const DisplayActionEvent& displayActionEvent, + const StdFunctionCommand::ActionFunction& actionFunction, + const StdFunctionCommand::FilterFunction& filterFunction) +{ + if (m_ObservableBroadcast.IsExpired()) + { + mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before connecting events."; + } + + auto observableBroadcast = m_ObservableBroadcast.Lock(); + auto command = StdFunctionCommand::New(); + command->SetCommandAction(actionFunction); + command->SetCommandFilter(filterFunction); + OberserverTagType tag = observableBroadcast->AddObserver(displayActionEvent, command); + m_ObserverTags.push_back(tag); + return tag; +} + +void mitk::DisplayActionEventHandler::DisconnectObserver(OberserverTagType observerTag) +{ + if (m_ObservableBroadcast.IsExpired()) + { + mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before disconnecting observer."; + } + + auto observableBroadcast = m_ObservableBroadcast.Lock(); + std::vector::iterator observerTagPosition = std::find(m_ObserverTags.begin(), m_ObserverTags.end(), observerTag); + if (observerTagPosition != m_ObserverTags.end()) + { + observableBroadcast->RemoveObserver(observerTag); + m_ObserverTags.erase(observerTagPosition); + } +} diff --git a/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp b/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp index 229a555fdb..bf8a7f9abe 100644 --- a/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp @@ -1,945 +1,951 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayInteractor.h" + #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkInteractionPositionEvent.h" #include "mitkPropertyList.h" #include #include #include // level window #include "mitkLevelWindow.h" #include "mitkLevelWindowProperty.h" #include "mitkLine.h" #include "mitkNodePredicateDataType.h" #include "mitkStandaloneDataStorage.h" #include "vtkRenderWindowInteractor.h" // Rotation #include "mitkInteractionConst.h" #include "rotate_cursor.xpm" #include #include #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include "mitkStatusBar.h" #include void mitk::DisplayInteractor::Notify(InteractionEvent *interactionEvent, bool isHandled) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { - this->HandleEvent(interactionEvent, nullptr); + HandleEvent(interactionEvent, nullptr); } } +mitk::DisplayInteractor::DisplayInteractor() + : m_IndexToSliceModifier(4) + , m_AutoRepeat(false) + , m_InvertScrollDirection(false) + , m_InvertZoomDirection(false) + , m_InvertMoveDirection(false) + , m_InvertLevelWindowDirection(false) + , m_AlwaysReact(false) + , m_ZoomFactor(2) + , m_LinkPlanes(true) +{ + m_StartCoordinateInMM.Fill(0); + m_LastDisplayCoordinate.Fill(0); + m_LastCoordinateInMM.Fill(0); + m_CurrentDisplayCoordinate.Fill(0); +} + +mitk::DisplayInteractor::~DisplayInteractor() +{ + // nothing here +} + void mitk::DisplayInteractor::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); CONNECT_FUNCTION("IncreaseTimeStep", IncreaseTimeStep); CONNECT_FUNCTION("DecreaseTimeStep", DecreaseTimeStep); } -mitk::DisplayInteractor::DisplayInteractor() - : m_IndexToSliceModifier(4), - m_AutoRepeat(false), - m_InvertScrollDirection(false), - m_InvertZoomDirection(false), - m_InvertMoveDirection(false), - m_InvertLevelWindowDirection(false), - m_AlwaysReact(false), - m_ZoomFactor(2), - m_LinkPlanes(true) -{ - m_StartCoordinateInMM.Fill(0); - m_LastDisplayCoordinate.Fill(0); - m_LastCoordinateInMM.Fill(0); - m_CurrentDisplayCoordinate.Fill(0); -} - -mitk::DisplayInteractor::~DisplayInteractor() -{ -} - bool mitk::DisplayInteractor::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) { return false; } return true; } bool mitk::DisplayInteractor::CheckRotationPossible(const mitk::InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - if there is NO interesection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto *posEvent = dynamic_cast(interactionEvent); if (posEvent == nullptr) return false; BaseRenderer *clickedRenderer = posEvent->GetSender(); const PlaneGeometry *ourViewportGeometry = (clickedRenderer->GetCurrentWorldPlaneGeometry()); if (!ourViewportGeometry) return false; Point3D cursorPosition = posEvent->GetPositionInWorld(); const auto spacing = ourViewportGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); const double threshholdDistancePixels = 12.0; auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; const PlaneGeometry *otherRenderersRenderPlane = snc->GetCurrentPlaneGeometry(); if (otherRenderersRenderPlane == nullptr) continue; // ignore, we don't see a plane // check if there is an intersection Line3D intersectionLine; // between rendered/clicked geometry and the one being analyzed if (!ourViewportGeometry->IntersectionLine(otherRenderersRenderPlane, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line const double distanceFromIntersectionLine = intersectionLine.Distance(cursorPosition) / spacing[snc->GetDefaultViewDirection()]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { anyOtherGeometry = otherRenderersRenderPlane; // we just take the last one, so overwrite each iteration (we just // need some crossing point) // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used if (m_LinkPlanes) { m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (geometryToBeRotated == nullptr) // first one close to the cursor { geometryToBeRotated = otherRenderersRenderPlane; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < mitk::eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); if (geometryToBeRotated && anyOtherGeometry && ourViewportGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { // we DO have enough information for rotation m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project( cursorPosition); // remember where the last cursor position ON THE LINE has been observed if (anyOtherGeometry->IntersectionPoint( intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) // find center of rotation by intersection with any of the OTHER lines { return true; } else { return false; } } return false; } bool mitk::DisplayInteractor::CheckSwivelPossible(const mitk::InteractionEvent *interactionEvent) { const ScalarType ThresholdDistancePixels = 6.0; // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto *posEvent = dynamic_cast(interactionEvent); BaseRenderer *renderer = interactionEvent->GetSender(); if (!posEvent || !renderer) return false; const Point3D &cursor = posEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry *clickedGeometry(nullptr); const PlaneGeometry *otherGeometry1(nullptr); const PlaneGeometry *otherGeometry2(nullptr); auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; // unsigned int slice = (*iter)->GetSlice()->GetPos(); // unsigned int time = (*iter)->GetTime()->GetPos(); const PlaneGeometry *planeGeometry = snc->GetCurrentPlaneGeometry(); if (!planeGeometry) continue; if (snc == renderer->GetSliceNavigationController()) { clickedGeometry = planeGeometry; m_SNCsToBeRotated.push_back(snc); } else { if (otherGeometry1 == nullptr) { otherGeometry1 = planeGeometry; } else { otherGeometry2 = planeGeometry; } if (m_LinkPlanes) { // If planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } mitk::Line3D line; mitk::Point3D point; if ((clickedGeometry != nullptr) && (otherGeometry1 != nullptr) && (otherGeometry2 != nullptr) && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; if (m_CenterOfRotation.EuclideanDistanceTo(cursor) < ThresholdDistancePixels) { return false; } else { m_ReferenceCursor = posEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = {1.0, 0.0, 0.0}; ScalarType yVector[] = {0.0, 1.0, 0.0}; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayInteractor::Init(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); m_LastCoordinateInMM = m_StartCoordinateInMM; } void mitk::DisplayInteractor::Move(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer *sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); float invertModifier = -1.0; if (m_InvertMoveDirection) { invertModifier = 1.0; } // perform translation Vector2D moveVector = (positionEvent->GetPointerPositionOnScreen() - m_LastDisplayCoordinate) * invertModifier; moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); + sender->GetCameraController()->MoveBy(moveVector); sender->GetRenderingManager()->RequestUpdate(sender->GetRenderWindow()); m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); } void mitk::DisplayInteractor::SetCrosshair(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { - const BaseRenderer::Pointer sender = interactionEvent->GetSender(); - auto renWindows = sender->GetRenderingManager()->GetAllRegisteredRenderWindows(); - auto *positionEvent = static_cast(interactionEvent); + auto* positionEvent = static_cast(interactionEvent); Point3D pos = positionEvent->GetPositionInWorld(); + const BaseRenderer::Pointer sender = interactionEvent->GetSender(); + auto renWindows = sender->GetRenderingManager()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { - if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard2D && - renWin != sender->GetRenderWindow()) + if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard2D && renWin != sender->GetRenderWindow()) + { BaseRenderer::GetInstance(renWin)->GetSliceNavigationController()->SelectSliceByPoint(pos); + } } } void mitk::DisplayInteractor::IncreaseTimeStep(StateMachineAction *, InteractionEvent *interactionEvent) { auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Next(); } void mitk::DisplayInteractor::DecreaseTimeStep(StateMachineAction *, InteractionEvent *interactionEvent) { auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Previous(); } void mitk::DisplayInteractor::Zoom(StateMachineAction *, InteractionEvent *interactionEvent) { - const BaseRenderer::Pointer sender = interactionEvent->GetSender(); - auto *positionEvent = static_cast(interactionEvent); - float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } + auto* positionEvent = static_cast(interactionEvent); + m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; + m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + if (factor != 1.0) { + const BaseRenderer::Pointer sender = interactionEvent->GetSender(); sender->GetCameraController()->Zoom(factor, m_StartCoordinateInMM); sender->GetRenderingManager()->RequestUpdate(sender->GetRenderWindow()); } - - m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; - m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); } void mitk::DisplayInteractor::Scroll(StateMachineAction *, InteractionEvent *interactionEvent) { - auto *positionEvent = static_cast(interactionEvent); + auto* positionEvent = static_cast(interactionEvent); - mitk::SliceNavigationController::Pointer sliceNaviController = - interactionEvent->GetSender()->GetSliceNavigationController(); + mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (sliceNaviController) { int delta = 0; // Scrolling direction if (m_ScrollDirection == "updown") { delta = static_cast(m_LastDisplayCoordinate[1] - positionEvent->GetPointerPositionOnScreen()[1]); } else { delta = static_cast(m_LastDisplayCoordinate[0] - positionEvent->GetPointerPositionOnScreen()[0]); } if (m_InvertScrollDirection) { delta *= -1; } // Set how many pixels the mouse has to be moved to scroll one slice // if we moved less than 'm_IndexToSliceModifier' pixels slice ONE slice only if (delta > 0 && delta < m_IndexToSliceModifier) { delta = m_IndexToSliceModifier; } else if (delta < 0 && delta > -m_IndexToSliceModifier) { delta = -m_IndexToSliceModifier; } delta /= m_IndexToSliceModifier; int newPos = sliceNaviController->GetSlice()->GetPos() + delta; // if auto repeat is on, start at first slice if you reach the last slice and vice versa int maxSlices = sliceNaviController->GetSlice()->GetSteps(); if (m_AutoRepeat) { while (newPos < 0) { newPos += maxSlices; } while (newPos >= maxSlices) { newPos -= maxSlices; } } else { // if the new slice is below 0 we still show slice 0 // due to the stepper using unsigned int we have to do this ourselves if (newPos < 1) { newPos = 0; } } - // set the new position - sliceNaviController->GetSlice()->SetPos(newPos); + m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); + + // set the new position + sliceNaviController->GetSlice()->SetPos(newPos); } } void mitk::DisplayInteractor::ScrollOneDown(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (!sliceNaviController->GetSliceLocked()) { mitk::Stepper *stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } stepper->Next(); } } void mitk::DisplayInteractor::ScrollOneUp(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (!sliceNaviController->GetSliceLocked()) { mitk::Stepper *stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } stepper->Previous(); } } void mitk::DisplayInteractor::AdjustLevelWindow(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer::Pointer sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // search for active image mitk::DataStorage::Pointer storage = sender->GetDataStorage(); mitk::DataNode::Pointer node = nullptr; - mitk::DataStorage::SetOfObjects::ConstPointer allImageNodes = - storage->GetSubset(mitk::NodePredicateDataType::New("Image")); - for (unsigned int i = 0; i < allImageNodes->size(); i++) + mitk::DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(mitk::NodePredicateDataType::New("Image")); + for (unsigned int i = 0; i < allImageNodes->size(); ++i) { bool isActiveImage = false; bool propFound = allImageNodes->at(i)->GetBoolProperty("imageForLevelWindow", isActiveImage); if (propFound && isActiveImage) { node = allImageNodes->at(i); continue; } } if (node.IsNull()) { node = storage->GetNode(mitk::NodePredicateDataType::New("Image")); } if (node.IsNull()) { return; } mitk::LevelWindow lv = mitk::LevelWindow(); node->GetLevelWindow(lv); ScalarType level = lv.GetLevel(); ScalarType window = lv.GetWindow(); int levelIndex = 0; int windowIndex = 1; if (m_LevelDirection != "leftright") { levelIndex = 1; windowIndex = 0; } int directionModifier = 1; if (m_InvertLevelWindowDirection) { directionModifier = -1; } // calculate adjustments from mouse movements level += (m_CurrentDisplayCoordinate[levelIndex] - m_LastDisplayCoordinate[levelIndex]) * static_cast(2) * directionModifier; window += (m_CurrentDisplayCoordinate[windowIndex] - m_LastDisplayCoordinate[windowIndex]) * static_cast(2) * directionModifier; lv.SetLevelWindow(level, window); dynamic_cast(node->GetProperty("levelwindow"))->SetLevelWindow(lv); sender->GetRenderingManager()->RequestUpdateAll(); } void mitk::DisplayInteractor::StartRotation(mitk::StateMachineAction *, mitk::InteractionEvent *) { this->SetMouseCursor(rotate_cursor_xpm, 0, 0); } void mitk::DisplayInteractor::EndRotation(mitk::StateMachineAction *, mitk::InteractionEvent *) { this->ResetMouseCursor(); } void mitk::DisplayInteractor::Rotate(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto *posEvent = dynamic_cast(event); if (posEvent == nullptr) return; Point3D cursor = posEvent->GetPositionInWorld(); Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; Vector3D toCursor = cursor - m_CenterOfRotation; // cross product: | A x B | = |A| * |B| * sin(angle) Vector3D axisOfRotation; vnl_vector_fixed vnlDirection = vnl_cross_3d(toCursor.GetVnlVector(), toProjected.GetVnlVector()); axisOfRotation.SetVnlVector(vnlDirection); // scalar product: A * B = |A| * |B| * cos(angle) // tan = sin / cos ScalarType angle = -atan2((double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected)); angle *= 180.0 / vnl_math::pi; m_LastCursorPosition = cursor; // create RotationOperation and apply to all SNCs that should be rotated RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); // iterate the OTHER slice navigation controllers: these are filled in DoDecideBetweenRotationAndSliceSelection for (auto iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; timeGeometry->ExecuteOperation(&rotationOperation); (*iter)->SendCreatedWorldGeometryUpdate(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::DisplayInteractor::Swivel(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto *posEvent = dynamic_cast(event); if (!posEvent) return; // Determine relative mouse movement projected onto world space Point2D cursor = posEvent->GetPointerPositionOnScreen(); Vector2D relativeCursor = cursor - m_ReferenceCursor; Vector3D relativeCursorAxis = m_RotationPlaneXVector * relativeCursor[0] + m_RotationPlaneYVector * relativeCursor[1]; // Determine rotation axis (perpendicular to rotation plane and cursor // movement) Vector3D rotationAxis = itk::CrossProduct(m_RotationPlaneNormal, relativeCursorAxis); ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0; // Restore the initial plane pose by undoing the previous rotation // operation RotationOperation op(OpROTATE, m_CenterOfRotation, m_PreviousRotationAxis, -m_PreviousRotationAngle); SNCVector::iterator iter; for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; timeGeometry->ExecuteOperation(&op); (*iter)->SendCreatedWorldGeometryUpdate(); } } // Apply new rotation operation to all relevant SNCs RotationOperation op2(OpROTATE, m_CenterOfRotation, rotationAxis, rotationAngle); for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { // Retrieve the TimeGeometry of this SliceNavigationController TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; // Execute the new rotation timeGeometry->ExecuteOperation(&op2); // Notify listeners (*iter)->SendCreatedWorldGeometryUpdate(); } } m_PreviousRotationAxis = rotationAxis; m_PreviousRotationAngle = rotationAngle; RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::DisplayInteractor::UpdateStatusbar(mitk::StateMachineAction *, mitk::InteractionEvent *event) { - const auto *posEvent = dynamic_cast(event); - - if (!posEvent) + const auto* posEvent = dynamic_cast(event); + if (nullptr == posEvent) + { return; + } - std::string statusText; + const mitk::BaseRenderer::Pointer baseRenderer = posEvent->GetSender(); TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); - - mitk::BaseRenderer* baseRenderer = posEvent->GetSender(); auto globalCurrentTimePoint = baseRenderer->GetTime(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = baseRenderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); + if (nodes.IsNull()) + { + return; + } // posEvent->GetPositionInWorld() would return the world position at the // time of initiating the interaction. However, we need to update the // status bar with the position after changing slice. Therefore, we // translate the same display position with the renderer again to // get the new world position. Point3D worldposition; - event->GetSender()->DisplayToWorld(posEvent->GetPointerPositionOnScreen(), worldposition); + baseRenderer->DisplayToWorld(posEvent->GetPointerPositionOnScreen(), worldposition); mitk::Image::Pointer image3D; mitk::DataNode::Pointer node; mitk::DataNode::Pointer topSourceNode; int component = 0; node = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, baseRenderer); - if (node.IsNotNull()) + if (node.IsNull()) { - bool isBinary(false); - node->GetBoolProperty("binary", isBinary); - if (isBinary) + return; + } + + bool isBinary(false); + node->GetBoolProperty("binary", isBinary); + if (isBinary) + { + mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = baseRenderer->GetDataStorage()->GetSources(node, nullptr, true); + if (!sourcenodes->empty()) { - mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = baseRenderer->GetDataStorage()->GetSources(node, nullptr, true); - if (!sourcenodes->empty()) - { topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, worldposition, globalCurrentTimePoint, baseRenderer); - } - if (topSourceNode.IsNotNull()) - { + } + if (topSourceNode.IsNotNull()) + { image3D = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } - } - else - { - image3D = dynamic_cast(node->GetData()); - node->GetIntProperty("Image.Displayed Component", component); - } - } + } + else + { + image3D = dynamic_cast(node->GetData()); + node->GetIntProperty("Image.Displayed Component", component); + } // get the position and gray value from the image and build up status bar text auto statusBar = StatusBar::GetInstance(); - if (image3D.IsNotNull() && statusBar != nullptr) { itk::Index<3> p; image3D->GetGeometry()->WorldToIndex(worldposition, p); auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); - if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) { std::string pixelValue = "Pixel RGB(A) value: "; pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue.c_str()); } - else if ( pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR ) + else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) { std::string pixelValue = "See ODF Details view. "; statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue.c_str()); } else { mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image3D->GetChannelDescriptor().GetPixelType(), image3D, image3D->GetVolumeData(image3D->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), p, pixelValue, component); statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue); } } else { statusBar->DisplayImageInfoInvalid(); } } void mitk::DisplayInteractor::ConfigurationChanged() { mitk::PropertyList::Pointer properties = GetAttributes(); // auto repeat std::string strAutoRepeat = ""; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } else { m_AutoRepeat = false; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } else { m_IndexToSliceModifier = 4; } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") m_LinkPlanes = true; else m_LinkPlanes = false; } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } // allwaysReact std::string strAlwaysReact = ""; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } else { m_AlwaysReact = false; } } else { m_AlwaysReact = false; } } bool mitk::DisplayInteractor::FilterEvents(InteractionEvent *interactionEvent, DataNode * /*dataNode*/) { if (interactionEvent->GetSender() == nullptr) return false; if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard3D) return false; return true; } bool mitk::DisplayInteractor::GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char *propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/Core/src/Interactions/mitkInteractionSchemeSwitcher.cpp b/Modules/Core/src/Interactions/mitkInteractionSchemeSwitcher.cpp new file mode 100644 index 0000000000..5cb7f5eb82 --- /dev/null +++ b/Modules/Core/src/Interactions/mitkInteractionSchemeSwitcher.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "mitkInteractionSchemeSwitcher.h" + +// us +#include "usGetModuleContext.h" +#include "usModuleContext.h" + +// mitk core +#include "mitkInteractionEventObserver.h" + +mitk::InteractionSchemeSwitcher::InteractionSchemeSwitcher() + : m_InteractionScheme(MITKStandard) +{ + // nothing here +} + +mitk::InteractionSchemeSwitcher::~InteractionSchemeSwitcher() +{ + // nothing here +} + +void mitk::InteractionSchemeSwitcher::SetInteractionScheme(mitk::InteractionEventHandler* interactionEventHandler, InteractionScheme interactionScheme) +{ + switch (interactionScheme) + { + // MITK MODE + case MITKStandard: + { + interactionEventHandler->SetEventConfig("DisplayConfigMITK.xml"); + break; + } + case MITKRotationUncoupled: + { + interactionEventHandler->SetEventConfig("DisplayConfigMITKRotationUnCoupled.xml"); + break; + } + case MITKRotationCoupled: + { + interactionEventHandler->SetEventConfig("DisplayConfigMITKRotation.xml"); + break; + } + case MITKSwivel: + { + interactionEventHandler->SetEventConfig("DisplayConfigMITKSwivel.xml"); + break; + } + // PACS MODE + case PACSStandard: + { + interactionEventHandler->SetEventConfig("DisplayConfigPACS.xml"); + break; + } + case PACSLevelWindow: + { + interactionEventHandler->SetEventConfig("DisplayConfigPACS.xml"); + interactionEventHandler->AddEventConfig("DisplayConfigPACSLevelWindow.xml"); + break; + } + case PACSPan: + { + interactionEventHandler->SetEventConfig("DisplayConfigPACS.xml"); + interactionEventHandler->AddEventConfig("DisplayConfigPACSPan.xml"); + break; + } + case PACSScroll: + { + interactionEventHandler->SetEventConfig("DisplayConfigPACS.xml"); + interactionEventHandler->AddEventConfig("DisplayConfigPACSScroll.xml"); + break; + } + case PACSZoom: + { + interactionEventHandler->SetEventConfig("DisplayConfigPACS.xml"); + interactionEventHandler->AddEventConfig("DisplayConfigPACSZoom.xml"); + break; + } + } + + m_InteractionScheme = interactionScheme; + InvokeEvent(InteractionSchemeChangedEvent()); +} diff --git a/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp b/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp new file mode 100644 index 0000000000..95bae2ae2a --- /dev/null +++ b/Modules/Core/src/Interactions/mitkStdDisplayActionEventHandler.cpp @@ -0,0 +1,45 @@ +/*=================================================================== + +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 "mitkDisplayActionEventFunctions.h" + +// itk +#include + +void mitk::StdDisplayActionEventHandler::InitStdActions() +{ + if (m_ObservableBroadcast.IsExpired()) + { + mitkThrow() << "No display action event broadcast class set to observe. Use 'SetObservableBroadcast' before initializing actions."; + } + + auto observableBroadcast = m_ObservableBroadcast.Lock(); + + StdFunctionCommand::ActionFunction actionFunction = DisplayActionEventFunctions::MoveSenderCameraAction(); + ConnectDisplayActionEvent(DisplayMoveEvent(nullptr, Vector2D()), actionFunction); + + actionFunction = DisplayActionEventFunctions::SetCrosshairAction(); + ConnectDisplayActionEvent(DisplaySetCrosshairEvent(nullptr, Point3D()), actionFunction); + + actionFunction = DisplayActionEventFunctions::ZoomSenderCameraAction(); + ConnectDisplayActionEvent(DisplayZoomEvent(nullptr, 0.0, Point2D()), actionFunction); + + actionFunction = DisplayActionEventFunctions::ScrollSliceStepperAction(); + ConnectDisplayActionEvent(DisplayScrollEvent(nullptr, 0), actionFunction); +} diff --git a/Modules/Core/src/Rendering/mitkImageVtkMapper2D.cpp b/Modules/Core/src/Rendering/mitkImageVtkMapper2D.cpp index bf8dae62d6..af882dd13b 100644 --- a/Modules/Core/src/Rendering/mitkImageVtkMapper2D.cpp +++ b/Modules/Core/src/Rendering/mitkImageVtkMapper2D.cpp @@ -1,1124 +1,1124 @@ /*=================================================================== 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. ===================================================================*/ // MITK #include #include #include #include #include #include #include #include #include #include #include //#include #include "mitkImageStatisticsHolder.h" #include "mitkPlaneClipping.h" #include // MITK Rendering #include "mitkImageVtkMapper2D.h" #include "vtkMitkLevelWindowFilter.h" #include "vtkMitkThickSlicesFilter.h" #include "vtkNeverTranslucentTexture.h" // VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ITK #include #include mitk::ImageVtkMapper2D::ImageVtkMapper2D() { } mitk::ImageVtkMapper2D::~ImageVtkMapper2D() { // The 3D RW Mapper (PlaneGeometryDataVtkMapper3D) is listening to this event, // in order to delete the images from the 3D RW. this->InvokeEvent(itk::DeleteEvent()); } // set the two points defining the textured plane according to the dimension and spacing void mitk::ImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer *renderer, double planeBounds[6]) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); float depth = this->CalculateLayerDepth(renderer); // Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct // plane size in crosshair rotation and swivel mode. localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); // These two points define the axes of the plane in combination with the origin. // Point 1 is the x-axis and point 2 the y-axis. // Each plane is transformed according to the view (axial, coronal and saggital) afterwards. localStorage->m_Plane->SetPoint1(planeBounds[1], planeBounds[2], depth); // P1: (xMax, yMin, depth) localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); // P2: (xMin, yMax, depth) } float mitk::ImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer *renderer) { // get the clipping range to check how deep into z direction we can render images double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1]; // Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined float depth = -maxRange * 0.01; // divide by 100 int layer = 0; GetDataNode()->GetIntProperty("layer", layer, renderer); // add the layer property for each image to render images with a higher layer on top of the others depth += layer * 10; //*10: keep some room for each image (e.g. for ODFs in between) if (depth > 0.0f) { depth = 0.0f; MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead."; } return depth; } const mitk::Image *mitk::ImageVtkMapper2D::GetInput(void) { return static_cast(GetDataNode()->GetData()); } vtkProp *mitk::ImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer *renderer) { // return the actor corresponding to the renderer return m_LSH.GetLocalStorage(renderer)->m_Actors; } void mitk::ImageVtkMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); auto *image = const_cast(this->GetInput()); mitk::DataNode *datanode = this->GetDataNode(); if (nullptr == image || !image->IsInitialized()) { return; } // check if there is a valid worldGeometry const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry(); if (nullptr == worldGeometry || !worldGeometry->IsValid() || !worldGeometry->HasReferenceGeometry()) { return; } image->Update(); // early out if there is no intersection of the current rendering geometry // and the geometry of the image that is to be rendered. if (!RenderingGeometryIntersectsImage(worldGeometry, image->GetSlicedGeometry())) { // set image to nullptr, to clear the texture in 3D, because // the latest image is used there if the plane is out of the geometry // see bug-13275 localStorage->m_ReslicedImage = nullptr; localStorage->m_Mapper->SetInputData(localStorage->m_EmptyPolyData); return; } // set main input for ExtractSliceFilter localStorage->m_Reslicer->SetInput(image); localStorage->m_Reslicer->SetWorldGeometry(worldGeometry); localStorage->m_Reslicer->SetTimeStep(this->GetTimestep()); // set the transformation of the image to adapt reslice axis localStorage->m_Reslicer->SetResliceTransformByGeometry( image->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep())); // is the geometry of the slice based on the input image or the worldgeometry? bool inPlaneResampleExtentByGeometry = false; datanode->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer); localStorage->m_Reslicer->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry); // Initialize the interpolation mode for resampling; switch to nearest // neighbor if the input image is too small. if ((image->GetDimension() >= 3) && (image->GetDimension(2) > 1)) { VtkResliceInterpolationProperty *resliceInterpolationProperty; datanode->GetProperty(resliceInterpolationProperty, "reslice interpolation", renderer); int interpolationMode = VTK_RESLICE_NEAREST; if (resliceInterpolationProperty != nullptr) { interpolationMode = resliceInterpolationProperty->GetInterpolation(); } switch (interpolationMode) { case VTK_RESLICE_NEAREST: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); break; case VTK_RESLICE_LINEAR: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_LINEAR); break; case VTK_RESLICE_CUBIC: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_CUBIC); break; } } else { localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); } // set the vtk output property to true, makes sure that no unneeded mitk image convertion // is done. localStorage->m_Reslicer->SetVtkOutputRequest(true); // Thickslicing int thickSlicesMode = 0; int thickSlicesNum = 1; // Thick slices parameters if (image->GetPixelType().GetNumberOfComponents() == 1) // for now only single component are allowed { DataNode *dn = renderer->GetCurrentWorldPlaneGeometryNode(); if (dn) { ResliceMethodProperty *resliceMethodEnumProperty = nullptr; if (dn->GetProperty(resliceMethodEnumProperty, "reslice.thickslices", renderer) && resliceMethodEnumProperty) thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); IntProperty *intProperty = nullptr; if (dn->GetProperty(intProperty, "reslice.thickslices.num", renderer) && intProperty) { thickSlicesNum = intProperty->GetValue(); if (thickSlicesNum < 1) thickSlicesNum = 1; } } else { MITK_WARN << "no associated widget plane data tree node found"; } } const auto *planeGeometry = dynamic_cast(worldGeometry); if (thickSlicesMode > 0) { double dataZSpacing = 1.0; Vector3D normInIndex, normal; const auto *abstractGeometry = dynamic_cast(worldGeometry); if (abstractGeometry != nullptr) normal = abstractGeometry->GetPlane()->GetNormal(); else { if (planeGeometry != nullptr) { normal = planeGeometry->GetNormal(); } else return; // no fitting geometry set } normal.Normalize(); image->GetTimeGeometry()->GetGeometryForTimeStep(this->GetTimestep())->WorldToIndex(normal, normInIndex); dataZSpacing = 1.0 / normInIndex.GetNorm(); localStorage->m_Reslicer->SetOutputDimensionality(3); localStorage->m_Reslicer->SetOutputSpacingZDirection(dataZSpacing); localStorage->m_Reslicer->SetOutputExtentZDirection(-thickSlicesNum, 0 + thickSlicesNum); // Do the reslicing. Modified() is called to make sure that the reslicer is // executed even though the input geometry information did not change; this // is necessary when the input /em data, but not the /em geometry changes. localStorage->m_TSFilter->SetThickSliceMode(thickSlicesMode - 1); localStorage->m_TSFilter->SetInputData(localStorage->m_Reslicer->GetVtkOutput()); // vtkFilter=>mitkFilter=>vtkFilter update mechanism will fail without calling manually localStorage->m_Reslicer->Modified(); localStorage->m_Reslicer->Update(); localStorage->m_TSFilter->Modified(); localStorage->m_TSFilter->Update(); localStorage->m_ReslicedImage = localStorage->m_TSFilter->GetOutput(); } else { // this is needed when thick mode was enable bevore. These variable have to be reset to default values localStorage->m_Reslicer->SetOutputDimensionality(2); localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0); localStorage->m_Reslicer->SetOutputExtentZDirection(0, 0); localStorage->m_Reslicer->Modified(); // start the pipeline with updating the largest possible, needed if the geometry of the input has changed localStorage->m_Reslicer->UpdateLargestPossibleRegion(); localStorage->m_ReslicedImage = localStorage->m_Reslicer->GetVtkOutput(); } // Bounds information for reslicing (only reuqired if reference geometry // is present) // this used for generating a vtkPLaneSource with the right size double sliceBounds[6]; for (auto &sliceBound : sliceBounds) { sliceBound = 0.0; } localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); // get the spacing of the slice localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); // calculate minimum bounding rect of IMAGE in texture { double textureClippingBounds[6]; for (auto &textureClippingBound : textureClippingBounds) { textureClippingBound = 0.0; } // Calculate the actual bounds of the transformed plane clipped by the // dataset bounding box; this is required for drawing the texture at the // correct position during 3D mapping. mitk::PlaneClipping::CalculateClippedPlaneBounds(image->GetGeometry(), planeGeometry, textureClippingBounds); textureClippingBounds[0] = static_cast(textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5); textureClippingBounds[1] = static_cast(textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5); textureClippingBounds[2] = static_cast(textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5); textureClippingBounds[3] = static_cast(textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5); // clipping bounds for cutting the image localStorage->m_LevelWindowFilter->SetClippingBounds(textureClippingBounds); } // get the number of scalar components to distinguish between different image types int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents(); // get the binary property bool binary = false; bool binaryOutline = false; datanode->GetBoolProperty("binary", binary, renderer); if (binary) // binary image { datanode->GetBoolProperty("outline binary", binaryOutline, renderer); if (binaryOutline) // contour rendering { // get pixel type of vtk image itk::ImageIOBase::IOComponentType componentType = static_cast(image->GetPixelType().GetComponentType()); switch (componentType) { case itk::ImageIOBase::UCHAR: // generate contours/outlines localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer); break; case itk::ImageIOBase::USHORT: // generate contours/outlines localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer); break; default: binaryOutline = false; this->ApplyLookuptable(renderer); MITK_WARN << "Type of all binary images should be unsigned char or unsigned short. Outline does not work on other pixel types!"; } if (binaryOutline) // binary outline is still true --> add outline { float binaryOutlineWidth = 1.0; if (datanode->GetFloatProperty("outline width", binaryOutlineWidth, renderer)) { if (localStorage->m_Actors->GetNumberOfPaths() > 1) { float binaryOutlineShadowWidth = 1.5; datanode->GetFloatProperty("outline shadow width", binaryOutlineShadowWidth, renderer); dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)) ->GetProperty() ->SetLineWidth(binaryOutlineWidth * binaryOutlineShadowWidth); } localStorage->m_Actor->GetProperty()->SetLineWidth(binaryOutlineWidth); } } } else // standard binary image { if (numberOfComponents != 1) { MITK_ERROR << "Rendering Error: Binary Images with more then 1 component are not supported!"; } } } this->ApplyOpacity(renderer); this->ApplyRenderingMode(renderer); // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter) localStorage->m_Texture->SetColorModeToDirectScalars(); int displayedComponent = 0; if (datanode->GetIntProperty("Image.Displayed Component", displayedComponent, renderer) && numberOfComponents > 1) { localStorage->m_VectorComponentExtractor->SetComponents(displayedComponent); localStorage->m_VectorComponentExtractor->SetInputData(localStorage->m_ReslicedImage); localStorage->m_LevelWindowFilter->SetInputConnection(localStorage->m_VectorComponentExtractor->GetOutputPort(0)); } else { // connect the input with the levelwindow filter localStorage->m_LevelWindowFilter->SetInputData(localStorage->m_ReslicedImage); } // check for texture interpolation property bool textureInterpolation = false; GetDataNode()->GetBoolProperty("texture interpolation", textureInterpolation, renderer); // set the interpolation modus according to the property localStorage->m_Texture->SetInterpolate(textureInterpolation); // connect the texture with the output of the levelwindow filter localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); this->TransformActor(renderer); auto *contourShadowActor = dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)); if (binary && binaryOutline) // connect the mapper with the polyData which contains the lines { // We need the contour for the binary outline property as actor localStorage->m_Mapper->SetInputData(localStorage->m_OutlinePolyData); localStorage->m_Actor->SetTexture(nullptr); // no texture for contours bool binaryOutlineShadow = false; datanode->GetBoolProperty("outline binary shadow", binaryOutlineShadow, renderer); if (binaryOutlineShadow) { contourShadowActor->SetVisibility(true); } else { contourShadowActor->SetVisibility(false); } } else { // Connect the mapper with the input texture. This is the standard case. // setup the textured plane this->GeneratePlane(renderer, sliceBounds); // set the plane as input for the mapper localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); // set the texture for the actor localStorage->m_Actor->SetTexture(localStorage->m_Texture); contourShadowActor->SetVisibility(false); } // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } void mitk::ImageVtkMapper2D::ApplyLevelWindow(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = this->GetLocalStorage(renderer); LevelWindow levelWindow; this->GetDataNode()->GetLevelWindow(levelWindow, renderer, "levelwindow"); localStorage->m_LevelWindowFilter->GetLookupTable()->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); mitk::LevelWindow opacLevelWindow; if (this->GetDataNode()->GetLevelWindow(opacLevelWindow, renderer, "opaclevelwindow")) { // pass the opaque level window to the filter localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); } else { // no opaque level window localStorage->m_LevelWindowFilter->SetMinOpacity(0.0); localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0); } } void mitk::ImageVtkMapper2D::ApplyColor(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = this->GetLocalStorage(renderer); float rgb[3] = {1.0f, 1.0f, 1.0f}; // check for color prop and use it for rendering if it exists // binary image hovering & binary image selection bool hover = false; bool selected = false; bool binary = false; GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); GetDataNode()->GetBoolProperty("selected", selected, renderer); GetDataNode()->GetBoolProperty("binary", binary, renderer); if (binary && hover && !selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty("binaryimage.hoveringcolor", renderer)); if (colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3 * sizeof(float)); } else { GetDataNode()->GetColor(rgb, renderer, "color"); } } if (binary && selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty("binaryimage.selectedcolor", renderer)); if (colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3 * sizeof(float)); } else { GetDataNode()->GetColor(rgb, renderer, "color"); } } if (!binary || (!hover && !selected)) { GetDataNode()->GetColor(rgb, renderer, "color"); } double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; // conversion to double for VTK dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); localStorage->m_Actor->GetProperty()->SetColor(rgbConv); if (localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1) { float rgb[3] = {1.0f, 1.0f, 1.0f}; mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty("outline binary shadow color", renderer)); if (colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3 * sizeof(float)); } double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; // conversion to double for VTK dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); } } void mitk::ImageVtkMapper2D::ApplyOpacity(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = this->GetLocalStorage(renderer); float opacity = 1.0f; // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity(opacity, renderer, "opacity"); // set the opacity according to the properties localStorage->m_Actor->GetProperty()->SetOpacity(opacity); if (localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1) { dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)) ->GetProperty() ->SetOpacity(opacity); } } void mitk::ImageVtkMapper2D::ApplyRenderingMode(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); bool binary = false; this->GetDataNode()->GetBoolProperty("binary", binary, renderer); if (binary) // is it a binary image? { // for binary images, we always use our default LuT and map every value to (0,1) // the opacity of 0 will always be 0.0. We never a apply a LuT/TfF nor a level window. localStorage->m_LevelWindowFilter->SetLookupTable(localStorage->m_BinaryLookupTable); } else { // all other image types can make use of the rendering mode int renderingMode = mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR; mitk::RenderingModeProperty::Pointer mode = dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Mode", renderer)); if (mode.IsNotNull()) { renderingMode = mode->GetRenderingMode(); } switch (renderingMode) { case mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR: MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_LookupTable_Color"; this->ApplyLookuptable(renderer); this->ApplyLevelWindow(renderer); break; case mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR: MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_ColorTransferFunction_Color"; this->ApplyColorTransferFunction(renderer); this->ApplyLevelWindow(renderer); break; case mitk::RenderingModeProperty::LOOKUPTABLE_COLOR: MITK_DEBUG << "'Image Rendering.Mode' = LookupTable_Color"; this->ApplyLookuptable(renderer); break; case mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR: MITK_DEBUG << "'Image Rendering.Mode' = ColorTransferFunction_Color"; this->ApplyColorTransferFunction(renderer); break; default: MITK_ERROR << "No valid 'Image Rendering.Mode' set. Using LOOKUPTABLE_LEVELWINDOW_COLOR instead."; this->ApplyLookuptable(renderer); this->ApplyLevelWindow(renderer); break; } } // we apply color for all images (including binaries). this->ApplyColor(renderer); } void mitk::ImageVtkMapper2D::ApplyLookuptable(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); vtkLookupTable *usedLookupTable = localStorage->m_ColorLookupTable; // If lookup table or transferfunction use is requested... mitk::LookupTableProperty::Pointer lookupTableProp = - dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); + dynamic_cast(this->GetDataNode()->GetProperty("LookupTable", renderer)); if (lookupTableProp.IsNotNull()) // is a lookuptable set? { usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); } else { //"Image Rendering.Mode was set to use a lookup table but there is no property 'LookupTable'. // A default (rainbow) lookup table will be used. // Here have to do nothing. Warning for the user has been removed, due to unwanted console output // in every interation of the rendering. } localStorage->m_LevelWindowFilter->SetLookupTable(usedLookupTable); } void mitk::ImageVtkMapper2D::ApplyColorTransferFunction(mitk::BaseRenderer *renderer) { mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast( this->GetDataNode()->GetProperty("Image Rendering.Transfer Function", renderer)); if (transferFunctionProp.IsNull()) { MITK_ERROR << "'Image Rendering.Mode'' was set to use a color transfer function but there is no property 'Image " "Rendering.Transfer Function'. Nothing will be done."; return; } LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); // pass the transfer function to our level window filter localStorage->m_LevelWindowFilter->SetLookupTable(transferFunctionProp->GetValue()->GetColorTransferFunction()); localStorage->m_LevelWindowFilter->SetOpacityPiecewiseFunction( transferFunctionProp->GetValue()->GetScalarOpacityFunction()); } void mitk::ImageVtkMapper2D::Update(mitk::BaseRenderer *renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) { return; } auto *data = const_cast(this->GetInput()); if (data == nullptr) { return; } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep(renderer); // Check if time step is valid const TimeGeometry *dataTimeGeometry = data->GetTimeGeometry(); if ((dataTimeGeometry == nullptr) || (dataTimeGeometry->CountTimeSteps() == 0) || (!dataTimeGeometry->IsValidTimeStep(this->GetTimestep()))) { return; } const DataNode *node = this->GetDataNode(); data->UpdateOutputInformation(); LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); // check if something important has changed and we need to rerender if ((localStorage->m_LastUpdateTime < node->GetMTime()) || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometryUpdateTime()) || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) || (localStorage->m_LastUpdateTime < data->GetPropertyList()->GetMTime())) { this->GenerateDataForRenderer(renderer); } // since we have checked that nothing important has changed, we can set // m_LastUpdateTime to the current time localStorage->m_LastUpdateTime.Modified(); } void mitk::ImageVtkMapper2D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { mitk::Image::Pointer image = dynamic_cast(node->GetData()); // Properties common for both images and segmentations node->AddProperty("depthOffset", mitk::FloatProperty::New(0.0), renderer, overwrite); node->AddProperty("outline binary", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("outline width", mitk::FloatProperty::New(1.0), renderer, overwrite); node->AddProperty("outline binary shadow", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("outline binary shadow color", ColorProperty::New(0.0, 0.0, 0.0), renderer, overwrite); node->AddProperty("outline shadow width", mitk::FloatProperty::New(1.5), renderer, overwrite); if (image->IsRotated()) node->AddProperty("reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC)); else node->AddProperty("reslice interpolation", mitk::VtkResliceInterpolationProperty::New()); node->AddProperty("texture interpolation", mitk::BoolProperty::New(false)); node->AddProperty("in plane resample extent by geometry", mitk::BoolProperty::New(false)); node->AddProperty("bounding box", mitk::BoolProperty::New(false)); mitk::RenderingModeProperty::Pointer renderingModeProperty = mitk::RenderingModeProperty::New(); node->AddProperty("Image Rendering.Mode", renderingModeProperty); // Set default grayscale look-up table mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); mitkLut->SetType(mitk::LookupTable::GRAYSCALE); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); - node->SetProperty("LookupTable", mitkLutProp); + node->SetProperty("LookupTable", mitkLutProp, renderer); std::string photometricInterpretation; // DICOM tag telling us how pixel values should be displayed if (node->GetStringProperty("dicom.pixel.PhotometricInterpretation", photometricInterpretation)) { // modality provided by DICOM or other reader if (photometricInterpretation.find("MONOCHROME1") != std::string::npos) // meaning: display MINIMUM pixels as WHITE { // Set inverse grayscale look-up table mitkLut->SetType(mitk::LookupTable::INVERSE_GRAYSCALE); mitkLutProp->SetLookupTable(mitkLut); - node->SetProperty("LookupTable", mitkLutProp); + node->SetProperty("LookupTable", mitkLutProp, renderer); renderingModeProperty->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); // USE lookuptable } // Otherwise do nothing - the default grayscale look-up table has already been set } bool isBinaryImage(false); if (!node->GetBoolProperty("binary", isBinaryImage) && image->GetPixelType().GetNumberOfComponents() == 1) { // ok, property is not set, use heuristic to determine if this // is a binary image mitk::Image::Pointer centralSliceImage; ScalarType minValue = 0.0; ScalarType maxValue = 0.0; ScalarType min2ndValue = 0.0; ScalarType max2ndValue = 0.0; mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); sliceSelector->SetInput(image); sliceSelector->SetSliceNr(image->GetDimension(2) / 2); sliceSelector->SetTimeNr(image->GetDimension(3) / 2); sliceSelector->SetChannelNr(image->GetDimension(4) / 2); sliceSelector->Update(); centralSliceImage = sliceSelector->GetOutput(); if (centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized()) { minValue = centralSliceImage->GetStatistics()->GetScalarValueMin(); maxValue = centralSliceImage->GetStatistics()->GetScalarValueMax(); min2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMin(); max2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMax(); } if ((maxValue == min2ndValue && minValue == max2ndValue) || minValue == maxValue) { // centralSlice is strange, lets look at all data minValue = image->GetStatistics()->GetScalarValueMin(); maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); } isBinaryImage = (maxValue == min2ndValue && minValue == max2ndValue); } std::string className = image->GetNameOfClass(); if (className != "TensorImage" && className != "OdfImage" && className != "ShImage") { PixelType pixelType = image->GetPixelType(); size_t numComponents = pixelType.GetNumberOfComponents(); if ((pixelType.GetPixelType() == itk::ImageIOBase::VECTOR && numComponents > 1) || numComponents == 2 || numComponents > 4) { node->AddProperty("Image.Displayed Component", mitk::IntProperty::New(0), renderer, overwrite); } } // some more properties specific for a binary... if (isBinaryImage) { node->AddProperty("opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite); node->AddProperty("color", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite); node->AddProperty("binaryimage.selectedcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite); node->AddProperty("binaryimage.selectedannotationcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite); node->AddProperty("binaryimage.hoveringcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite); node->AddProperty("binaryimage.hoveringannotationcolor", ColorProperty::New(1.0, 0.0, 0.0), renderer, overwrite); node->AddProperty("binary", mitk::BoolProperty::New(true), renderer, overwrite); node->AddProperty("layer", mitk::IntProperty::New(10), renderer, overwrite); } else //...or image type object { node->AddProperty("opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite); node->AddProperty("color", ColorProperty::New(1.0, 1.0, 1.0), renderer, overwrite); node->AddProperty("binary", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite); } if (image.IsNotNull() && image->IsInitialized()) { if ((overwrite) || (node->GetProperty("levelwindow", renderer) == nullptr)) { /* initialize level/window from DICOM tags */ std::string sLevel = ""; std::string sWindow = ""; if (GetBackwardsCompatibleDICOMProperty( 0x0028, 0x1050, "dicom.voilut.WindowCenter", image->GetPropertyList(), sLevel) && GetBackwardsCompatibleDICOMProperty( 0x0028, 0x1051, "dicom.voilut.WindowWidth", image->GetPropertyList(), sWindow)) { float level = atof(sLevel.c_str()); float window = atof(sWindow.c_str()); mitk::LevelWindow contrast; std::string sSmallestPixelValueInSeries; std::string sLargestPixelValueInSeries; if (GetBackwardsCompatibleDICOMProperty(0x0028, 0x0108, "dicom.series.SmallestPixelValueInSeries", image->GetPropertyList(), sSmallestPixelValueInSeries) && GetBackwardsCompatibleDICOMProperty(0x0028, 0x0109, "dicom.series.LargestPixelValueInSeries", image->GetPropertyList(), sLargestPixelValueInSeries)) { float smallestPixelValueInSeries = atof(sSmallestPixelValueInSeries.c_str()); float largestPixelValueInSeries = atof(sLargestPixelValueInSeries.c_str()); contrast.SetRangeMinMax(smallestPixelValueInSeries - 1, largestPixelValueInSeries + 1); // why not a little buffer? // might remedy some l/w widget challenges } else { contrast.SetAuto(static_cast(node->GetData()), false, true); // we need this as a fallback } contrast.SetLevelWindow(level, window, true); node->SetProperty("levelwindow", LevelWindowProperty::New(contrast), renderer); } } if (((overwrite) || (node->GetProperty("opaclevelwindow", renderer) == nullptr)) && (image->GetPixelType().GetPixelType() == itk::ImageIOBase::RGBA) && (image->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR)) { mitk::LevelWindow opaclevwin; opaclevwin.SetRangeMinMax(0, 255); opaclevwin.SetWindowBounds(0, 255); mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); node->SetProperty("opaclevelwindow", prop, renderer); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } mitk::ImageVtkMapper2D::LocalStorage *mitk::ImageVtkMapper2D::GetLocalStorage(mitk::BaseRenderer *renderer) { return m_LSH.GetLocalStorage(renderer); } template vtkSmartPointer mitk::ImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = this->GetLocalStorage(renderer); // get the min and max index values of each direction int *extent = localStorage->m_ReslicedImage->GetExtent(); int xMin = extent[0]; int xMax = extent[1]; int yMin = extent[2]; int yMax = extent[3]; int *dims = localStorage->m_ReslicedImage->GetDimensions(); // dimensions of the image int line = dims[0]; // how many pixels per line? int x = xMin; // pixel index x int y = yMin; // pixel index y // get the depth for each contour float depth = CalculateLayerDepth(renderer); vtkSmartPointer points = vtkSmartPointer::New(); // the points to draw vtkSmartPointer lines = vtkSmartPointer::New(); // the lines to connect the points // We take the pointer to the first pixel of the image auto* currentPixel = static_cast(localStorage->m_ReslicedImage->GetScalarPointer()); while (y <= yMax) { // if the current pixel value is set to something if ((currentPixel) && (*currentPixel != 0)) { // check in which direction a line is necessary // a line is added if the neighbor of the current pixel has the value 0 // and if the pixel is located at the edge of the image // if vvvvv not the first line vvvvv if (y > yMin && *(currentPixel - line) == 0) { // x direction - bottom edge of the pixel // add the 2 points vtkIdType p1 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); // add the line between both points lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } // if vvvvv not the last line vvvvv if (y < yMax && *(currentPixel + line) == 0) { // x direction - top edge of the pixel vtkIdType p1 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint( (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } // if vvvvv not the first pixel vvvvv if ((x > xMin || y > yMin) && *(currentPixel - 1) == 0) { // y direction - left edge of the pixel vtkIdType p1 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } // if vvvvv not the last pixel vvvvv if ((y < yMax || (x < xMax)) && *(currentPixel + 1) == 0) { // y direction - right edge of the pixel vtkIdType p1 = points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint( (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } /* now consider pixels at the edge of the image */ // if vvvvv left edge of image vvvvv if (x == xMin) { // draw left edge of the pixel vtkIdType p1 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } // if vvvvv right edge of image vvvvv if (x == xMax) { // draw right edge of the pixel vtkIdType p1 = points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint( (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } // if vvvvv bottom edge of image vvvvv if (y == yMin) { // draw bottom edge of the pixel vtkIdType p1 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint((x + 1) * localStorage->m_mmPerPixel[0], y * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } // if vvvvv top edge of image vvvvv if (y == yMax) { // draw top edge of the pixel vtkIdType p1 = points->InsertNextPoint(x * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); vtkIdType p2 = points->InsertNextPoint( (x + 1) * localStorage->m_mmPerPixel[0], (y + 1) * localStorage->m_mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } } // end if currentpixel is set x++; if (x > xMax) { // reached end of line x = xMin; y++; } // Increase the pointer-position to the next pixel. // This is safe, as the while-loop and the x-reset logic above makes // sure we do not exceed the bounds of the image currentPixel++; } // end of while // Create a polydata to store everything in vtkSmartPointer polyData = vtkSmartPointer::New(); // Add the points to the dataset polyData->SetPoints(points); // Add the lines to the dataset polyData->SetLines(lines); return polyData; } void mitk::ImageVtkMapper2D::TransformActor(mitk::BaseRenderer *renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); // get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); trans->SetMatrix(matrix); // transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital) localStorage->m_Actor->SetUserTransform(trans); // transform the origin to center based coordinates, because MITK is center based. localStorage->m_Actor->SetPosition(-0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0); if (localStorage->m_Actors->GetNumberOfPaths() > 1) { auto *secondaryActor = dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)); secondaryActor->SetUserTransform(trans); secondaryActor->SetPosition(-0.5 * localStorage->m_mmPerPixel[0], -0.5 * localStorage->m_mmPerPixel[1], 0.0); } } bool mitk::ImageVtkMapper2D::RenderingGeometryIntersectsImage(const PlaneGeometry *renderingGeometry, SlicedGeometry3D *imageGeometry) { // if either one of the two geometries is nullptr we return true // for safety reasons if (renderingGeometry == nullptr || imageGeometry == nullptr) return true; // get the distance for the first cornerpoint ScalarType initialDistance = renderingGeometry->SignedDistance(imageGeometry->GetCornerPoint(0)); for (int i = 1; i < 8; i++) { mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint(i); // get the distance to the other cornerpoints ScalarType distance = renderingGeometry->SignedDistance(cornerPoint); // if it has not the same signing as the distance of the first point if (initialDistance * distance < 0) { // we have an intersection and return true return true; } } // all distances have the same sign, no intersection and we return false return false; } mitk::ImageVtkMapper2D::LocalStorage::~LocalStorage() { } mitk::ImageVtkMapper2D::LocalStorage::LocalStorage() : m_VectorComponentExtractor(vtkSmartPointer::New()) { m_LevelWindowFilter = vtkSmartPointer::New(); // Do as much actions as possible in here to avoid double executions. m_Plane = vtkSmartPointer::New(); m_Texture = vtkSmartPointer::New().GetPointer(); m_DefaultLookupTable = vtkSmartPointer::New(); m_BinaryLookupTable = vtkSmartPointer::New(); m_ColorLookupTable = vtkSmartPointer::New(); m_Mapper = vtkSmartPointer::New(); m_Actor = vtkSmartPointer::New(); m_Actors = vtkSmartPointer::New(); m_Reslicer = mitk::ExtractSliceFilter::New(); m_TSFilter = vtkSmartPointer::New(); m_OutlinePolyData = vtkSmartPointer::New(); m_ReslicedImage = vtkSmartPointer::New(); m_EmptyPolyData = vtkSmartPointer::New(); // the following actions are always the same and thus can be performed // in the constructor for each image (i.e. the image-corresponding local storage) m_TSFilter->ReleaseDataFlagOn(); mitk::LookupTable::Pointer mitkLUT = mitk::LookupTable::New(); // built a default lookuptable mitkLUT->SetType(mitk::LookupTable::GRAYSCALE); m_DefaultLookupTable = mitkLUT->GetVtkLookupTable(); mitkLUT->SetType(mitk::LookupTable::LEGACY_BINARY); m_BinaryLookupTable = mitkLUT->GetVtkLookupTable(); mitkLUT->SetType(mitk::LookupTable::LEGACY_RAINBOW_COLOR); m_ColorLookupTable = mitkLUT->GetVtkLookupTable(); // do not repeat the texture (the image) m_Texture->RepeatOff(); // set the mapper for the actor m_Actor->SetMapper(m_Mapper); vtkSmartPointer outlineShadowActor = vtkSmartPointer::New(); outlineShadowActor->SetMapper(m_Mapper); m_Actors->AddPart(outlineShadowActor); m_Actors->AddPart(m_Actor); } diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index 3e96e687dd..ec5e57aa47 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,113 +1,124 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES QmitkAbstractDataStorageModel.cpp QmitkApplicationCursor.cpp QmitkDataStorageComboBox.cpp QmitkDataStorageDefaultListModel.cpp QmitkDataStorageListModel.cpp QmitkDataStorageTableModel.cpp QmitkDataStorageSimpleTreeModel.cpp QmitkDataStorageTreeModel.cpp QmitkDataStorageTreeModelInternalItem.cpp QmitkDnDDataNodeWidget.cpp QmitkFileReaderOptionsDialog.cpp QmitkFileReaderWriterOptionsWidget.cpp QmitkFileWriterOptionsDialog.cpp + QmitkInteractionSchemeToolBar.cpp QmitkIOUtil.cpp QmitkLevelWindowPresetDefinitionDialog.cpp QmitkLevelWindowRangeChangeDialog.cpp QmitkLevelWindowWidgetContextMenu.cpp QmitkLevelWindowWidget.cpp QmitkLineEditLevelWindowWidget.cpp QmitkMemoryUsageIndicatorView.cpp + QmitkMouseModeSwitcher.cpp QmitkMimeTypes.cpp + QmitkMultiWidgetConfigurationToolBar.cpp + QmitkMultiWidgetLayoutSelectionWidget.cpp QmitkNodeDescriptor.cpp QmitkColoredNodeDescriptor.cpp QmitkNodeDescriptorManager.cpp - QmitkRenderWindowMenu.cpp QmitkProgressBar.cpp QmitkPropertiesTableEditor.cpp QmitkPropertiesTableModel.cpp QmitkPropertyDelegate.cpp QmitkRegisterClasses.cpp QmitkRenderingManager.cpp QmitkRenderingManagerFactory.cpp QmitkRenderWindow.cpp + QmitkRenderWindowMenu.cpp + QmitkRenderWindowWidget.cpp QmitkServiceListWidget.cpp QmitkSliderLevelWindowWidget.cpp QmitkStdMultiWidget.cpp - QmitkMouseModeSwitcher.cpp - QmitkDataStorageFilterProxyModel.cpp + QmitkMxNMultiWidget.cpp QmitkDataStorageComboBoxWithSelectNone.cpp + QmitkDataStorageFilterProxyModel.cpp QmitkPropertyItem.cpp QmitkPropertyItemDelegate.cpp QmitkPropertyItemModel.cpp QmitkStyleManager.cpp QmitkAbstractDataStorageInspector.cpp QmitkDataStorageListInspector.cpp QmitkDataStorageTreeInspector.cpp QmitkModelViewSelectionConnector.cpp mitkIDataStorageInspectorProvider.cpp mitkQtWidgetsActivator.cpp mitkDataStorageInspectorGenerator.cpp QmitkOverlayWidget.cpp QmitkNodeDetailsDialog.cpp ) set(MOC_H_FILES include/QmitkAbstractDataStorageModel.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h include/QmitkDataStorageSimpleTreeModel.h include/QmitkDataStorageDefaultListModel.h include/QmitkDnDDataNodeWidget.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h + include/QmitkInteractionSchemeToolBar.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h + include/QmitkMouseModeSwitcher.h + include/QmitkMultiWidgetConfigurationToolBar.h + include/QmitkMultiWidgetLayoutSelectionWidget.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h - include/QmitkRenderWindowMenu.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h + include/QmitkRenderWindowMenu.h + include/QmitkRenderWindowWidget.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h - include/QmitkMouseModeSwitcher.h + include/QmitkMxNMultiWidget.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h include/QmitkDataStorageListInspector.h include/QmitkAbstractDataStorageInspector.h include/QmitkDataStorageTreeInspector.h include/QmitkModelViewSelectionConnector.h include/QmitkOverlayWidget.h include/QmitkNodeDetailsDialog.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui + src/QmitkMultiWidgetLayoutSelectionWidget.ui src/QmitkServiceListWidgetControls.ui src/QmitkDataStorageListInspector.ui src/QmitkDataStorageTreeInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h index 30faaec032..4ee22a0e26 100644 --- a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h @@ -1,92 +1,92 @@ /*=================================================================== 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 QMITKABSTRACTDATASTORAGEMODEL_H #define QMITKABSTRACTDATASTORAGEMODEL_H #include // mitk core #include #include #include // qt #include /* * @brief This abstract class extends the 'QAbstractItemModel' to accept an 'mitk::DataStorage' and a 'mitk::NodePredicateBase'. * It registers itself as a node event listener of the data storage. * The 'QmitkAbstractDataStorageModel' provides three empty functions, 'NodeAdded', 'NodeChanged' and 'NodeRemoved', that * may be implemented by subclasses. These functions allow to react to the 'AddNodeEvent', 'ChangedNodeEvent' and * 'RemoveNodeEvent' of the data storage. This might be useful to force an update on a custom view to correctly * represent the content of the data storage. * * A concrete implementation of this class is used to store the temporarily shown data nodes of the data storage. * These nodes may be a subset of all the nodes inside the data storage, if a specific node predicate is set. * * A model that implements this class has to return mitk::DataNode::Pointer objects for model indexes when the * role is QmitkDataNodeRole. */ class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageModel : public QAbstractItemModel { Q_OBJECT public: virtual ~QmitkAbstractDataStorageModel(); /* * @brief Sets the data storage and adds listener for node events. * * @param dataStorage A pointer to the data storage to set. */ void SetDataStorage(mitk::DataStorage* dataStorage); - mitk::DataStorage* GetDataStorage() { return m_DataStorage.Lock().GetPointer(); } + mitk::DataStorage* GetDataStorage() const; /* * @brief Sets the node predicate and updates the model data, according to the node predicate. * * @param nodePredicate A pointer to node predicate. */ void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); - mitk::NodePredicateBase* GetNodePredicate() { return m_NodePredicate; } + mitk::NodePredicateBase* GetNodePredicate() const { return m_NodePredicate; } protected: virtual void DataStorageChanged() = 0; virtual void NodePredicateChanged() = 0; virtual void NodeAdded(const mitk::DataNode* node) = 0; virtual void NodeChanged(const mitk::DataNode* node) = 0; virtual void NodeRemoved(const mitk::DataNode* node) = 0; QmitkAbstractDataStorageModel(QObject* parent = nullptr); QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent = nullptr); mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::Pointer m_NodePredicate; private: /** Helper triggered on the storage delete event */ void SetDataStorageDeleted(); unsigned long m_DataStorageDeletedTag; }; #endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkInteractionSchemeToolBar.h b/Modules/QtWidgets/include/QmitkInteractionSchemeToolBar.h new file mode 100644 index 0000000000..e9df9eb9a8 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkInteractionSchemeToolBar.h @@ -0,0 +1,60 @@ +/*=================================================================== + +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 QMITKINTERACTIONSCHEMETOOLBAR_H +#define QMITKINTERACTIONSCHEMETOOLBAR_H + +#include "MitkQtWidgetsExports.h" + +// mitk core +#include "mitkInteractionSchemeSwitcher.h" + +#include +#include + +/** +* @brief +* +* +*/ +class MITKQTWIDGETS_EXPORT QmitkInteractionSchemeToolBar : public QToolBar +{ + Q_OBJECT + +public: + + using InteractionScheme = mitk::InteractionSchemeSwitcher::InteractionScheme; + + QmitkInteractionSchemeToolBar(QWidget* parent = nullptr); + virtual ~QmitkInteractionSchemeToolBar() override; + + void SetInteractionEventHandler(mitk::InteractionEventHandler::Pointer interactionEventHandler); + +protected slots: + + void OnInteractionSchemeChanged(); + void AddButton(InteractionScheme id, const QString& toolName, const QIcon& icon, bool on = false); + +private: + + QActionGroup* m_ActionGroup; + + mitk::InteractionSchemeSwitcher::Pointer m_InteractionSchemeSwitcher; + mitk::InteractionEventHandler::Pointer m_InteractionEventHandler; + +}; + +#endif // QMITKINTERACTIONSCHEMETOOLBAR_H diff --git a/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h b/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h index 35701cef1c..4f1575c527 100644 --- a/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h +++ b/Modules/QtWidgets/include/QmitkMouseModeSwitcher.h @@ -1,89 +1,88 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkMouseModeSwitcher_h #define QmitkMouseModeSwitcher_h #include "MitkQtWidgetsExports.h" #include "mitkMouseModeSwitcher.h" #include #include /** * \ingroup QmitkModule * \brief Qt toolbar representing mitk::MouseModeSwitcher. * * Provides buttons for the interaction modes defined in mitk::MouseModeSwitcher * and communicates with this non-graphical class. * * Can be used in a GUI to provide a mouse mode selector to the user. */ class MITKQTWIDGETS_EXPORT QmitkMouseModeSwitcher : public QToolBar { Q_OBJECT public: - QmitkMouseModeSwitcher(QWidget *parent = nullptr); + + QmitkMouseModeSwitcher(QWidget* parent = nullptr); ~QmitkMouseModeSwitcher() override; typedef mitk::MouseModeSwitcher::MouseMode MouseMode; public slots: /** \brief Connect to non-GUI class. When a button is pressed, given mitk::MouseModeSwitcher is informed to adapt interactors. \todo QmitkMouseModeSwitcher could be enhanced to actively observe mitk::MouseModeSwitcher and change available actions or visibility appropriately. */ - void setMouseModeSwitcher(mitk::MouseModeSwitcher *); + void setMouseModeSwitcher(mitk::MouseModeSwitcher*); signals: /** \brief Mode activated. This signal is needed for other GUI element to react appropriately. Sadly this is needed to provide "normal" functionality of QmitkStdMultiWidget, because this must enable/disable automatic reaction of SliceNavigationControllers to mouse clicks - depending on which mode is active. */ - void MouseModeSelected(mitk::MouseModeSwitcher::MouseMode id); // TODO change int to enum of MouseModeSwitcher + void MouseModeSelected(MouseMode id); protected slots: - void modeSelectedByUser(); - void addButton(MouseMode id, - const QString &toolName, - const QIcon &icon, - bool on = false); // TODO change int to enum of MouseModeSwitcher + void OnMouseModeChangedViaButton(); + void addButton(MouseMode id, const QString& toolName, const QIcon& icon, bool on = false); protected: - void OnMouseModeChanged(const itk::EventObject &); - QActionGroup *m_ActionGroup; - mitk::MouseModeSwitcher *m_MouseModeSwitcher; + void OnMouseModeChangedViaCommand(const itk::EventObject&); + + QActionGroup* m_ActionGroup; + mitk::MouseModeSwitcher* m_MouseModeSwitcher; unsigned long m_ObserverTag; - bool m_InObservationReaction; + bool m_ActionButtonBlocked; }; #endif diff --git a/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h b/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h new file mode 100644 index 0000000000..89ca170d5b --- /dev/null +++ b/Modules/QtWidgets/include/QmitkMultiWidgetConfigurationToolBar.h @@ -0,0 +1,62 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H +#define QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H + +#include "MitkQtWidgetsExports.h" + +#include + +// mitk qtwidgets +#include "QmitkMultiWidgetLayoutSelectionWidget.h" + +/** +* @brief +* +* +*/ +class MITKQTWIDGETS_EXPORT QmitkMultiWidgetConfigurationToolBar : public QToolBar +{ + Q_OBJECT + +public: + + QmitkMultiWidgetConfigurationToolBar(); + ~QmitkMultiWidgetConfigurationToolBar() override; + +Q_SIGNALS: + + void LayoutSet(int row, int column); + void Synchronized(bool synchronized); + +protected Q_SLOTS: + + void OnSetLayout(); + void OnSynchronize(); + +private: + + void InitializeToolBar();; + void AddButtons(); + + QAction* m_SynchronizeAction; + + QmitkMultiWidgetLayoutSelectionWidget* m_LayoutSelectionPopup; + +}; + +#endif // QMITKMULTIWIDGETCONFIGURATIONTOOLBAR_H diff --git a/Modules/QtWidgets/include/QmitkMultiWidgetLayoutSelectionWidget.h b/Modules/QtWidgets/include/QmitkMultiWidgetLayoutSelectionWidget.h new file mode 100644 index 0000000000..65b46e63cf --- /dev/null +++ b/Modules/QtWidgets/include/QmitkMultiWidgetLayoutSelectionWidget.h @@ -0,0 +1,58 @@ +/*=================================================================== + +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 QMITKMULTIWIDGETLAYOUTSELECTIONWIDGET_H +#define QMITKMULTIWIDGETLAYOUTSELECTIONWIDGET_H + +#include "MitkQtWidgetsExports.h" + +#include "ui_QmitkMultiWidgetLayoutSelectionWidget.h" + +// qt +#include "QWidget" + +/** +* @brief +* +* +*/ +class MITKQTWIDGETS_EXPORT QmitkMultiWidgetLayoutSelectionWidget : public QWidget +{ + Q_OBJECT + +public: + + QmitkMultiWidgetLayoutSelectionWidget(QWidget* parent = 0); + +Q_SIGNALS: + + void LayoutSet(int row, int column); + +private Q_SLOTS: + + void OnTableItemSelectionChanged(); + void OnSetLayoutButtonClicked(); + +private: + + void Init(); + + + Ui::QmitkMultiWidgetLayoutSelectionWidget ui; + +}; + +#endif // QMITKMULTIWIDGETLAYOUTSELECTIONWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h new file mode 100644 index 0000000000..061aeea8f2 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h @@ -0,0 +1,152 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKMXNMULTIWIDGET_H +#define QMITKMXNMULTIWIDGET_H + +// qt widgets module +#include "MitkQtWidgetsExports.h" +#include "QmitkRenderWindowWidget.h" + +// mitk core +#include +#include +#include +#include + +// qt +#include + +class QHBoxLayout; +class QVBoxLayout; +class QGridLayout; +class QSpacerItem; +class QmitkRenderWindow; + +namespace mitk +{ + class RenderingManager; +} + +/** +* @brief The 'QmitkMxNMultiWidget' is a QWidget that is used to display multiple render windows at once. +* Render windows can dynamically be added and removed to change the layout of the multi widget. This +* is done by using the 'ResetLayout'-function to define a layout. This will automatically add or remove +* the appropriate number of render window widgets. +* Several functions exist to retrieve specific render window(s) (widgets) by their position or name. +* +* The class uses the 'DisplayActionEventBroadcast' and 'DisplayActionEventHandler' classes to +* load a state machine and set an event configuration. PACS mode is used per default. +* Using the 'Synchronize' function the user can enable or disable the synchronization of display action events. +* See 'DisplayActionEventFunctions'-class for the different synchronized and non-synchronized functions used. +*/ +class MITKQTWIDGETS_EXPORT QmitkMxNMultiWidget : public QWidget +{ + Q_OBJECT + +public: + + using RenderWindowWidgetPointer = std::shared_ptr; + using RenderWindowWidgetMap = std::map>; + using RenderWindowHash = QHash; + + QmitkMxNMultiWidget(QWidget* parent = 0, + Qt::WindowFlags f = 0, + mitk::RenderingManager* renderingManager = nullptr, + mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard, + const QString& multiWidgetName = "mxnmulti"); + + virtual ~QmitkMxNMultiWidget() = default; + + void SetDataStorage(mitk::DataStorage* dataStorage); + void InitializeRenderWindowWidgets(); + + mitk::InteractionEventHandler::Pointer GetInteractionEventHandler() { return m_DisplayActionEventBroadcast.GetPointer(); }; + + void ResetLayout(int row, int column); + void Synchronize(bool synchronized); + + RenderWindowWidgetMap GetRenderWindowWidgets() const; + RenderWindowWidgetPointer GetRenderWindowWidget(int row, int column) const; + RenderWindowWidgetPointer GetRenderWindowWidget(const QString& widgetName) const; + RenderWindowHash GetRenderWindows() const; + QmitkRenderWindow* GetRenderWindow(int row, int column) const; + QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const; + + void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget); + RenderWindowWidgetPointer GetActiveRenderWindowWidget() const; + RenderWindowWidgetPointer GetFirstRenderWindowWidget() const; + RenderWindowWidgetPointer GetLastRenderWindowWidget() const; + + unsigned int GetNumberOfRenderWindowWidgets() const; + + void RequestUpdate(const QString& widgetName); + void RequestUpdateAll(); + void ForceImmediateUpdate(const QString& widgetName); + void ForceImmediateUpdateAll(); + + void ActivateAllCrosshairs(bool activate); + const mitk::Point3D GetSelectedPosition(const QString& widgetName) const; + +public Q_SLOTS: + + void SetSelectedPosition(const QString& widgetName, const mitk::Point3D& newPosition); + + // mouse events + void wheelEvent(QWheelEvent* e) override; + + void mousePressEvent(QMouseEvent* e) override; + + void moveEvent(QMoveEvent* e) override; + +Q_SIGNALS: + + void WheelMoved(QWheelEvent *); + void Moved(); + +private: + + void InitializeGUI(); + void InitializeDisplayActionEventHandling(); + + void CreateRenderWindowWidget(); + void DestroyRenderWindowWidget(); + void FillMultiWidgetLayout(); + + QString GetNameFromIndex(int row, int column) const; + QString GetNameFromIndex(size_t index) const; + + QGridLayout* m_MxNMultiWidgetLayout; + RenderWindowWidgetMap m_RenderWindowWidgets; + + RenderWindowWidgetPointer m_ActiveRenderWindowWidget; + + int m_MultiWidgetRows; + int m_MultiWidgetColumns; + + int m_PlaneMode; + + mitk::RenderingManager* m_RenderingManager; + mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; + QString m_MultiWidgetName; + + mitk::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; + std::unique_ptr m_DisplayActionEventHandler; + + mitk::DataStorage::Pointer m_DataStorage; +}; + +#endif // QMITKMXNMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h new file mode 100644 index 0000000000..d74ff46a9c --- /dev/null +++ b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h @@ -0,0 +1,113 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKRENDERWINDOWWIDGET_H +#define QMITKRENDERWINDOWWIDGET_H + +// qt widgets module +#include "MitkQtWidgetsExports.h" +#include "QmitkRenderWindow.h" + +// mitk core +#include +#include +#include +#include +#include + +// qt +#include +#include + +/** +* @brief The 'QmitkRenderWindowWidget' is a QWidget that holds a render window +* and some associates properties, like a crosshair (pointset) and decorations. +* Decorations are corner annotation (text and color), frame color or background color +* and can be set using this class. +* The 'QmitkRenderWindowWidget' is used inside the 'QmitkMxNMultiWidget', where a map contains +* several render window widgets to create the MxN display. +*/ +class MITKQTWIDGETS_EXPORT QmitkRenderWindowWidget : public QWidget +{ + Q_OBJECT + +public: + + QmitkRenderWindowWidget( + QWidget* parent = nullptr, + const QString& widgetName = "", + mitk::DataStorage* dataStorage = nullptr, + mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::Standard + ); + + virtual ~QmitkRenderWindowWidget(); + + void SetDataStorage(mitk::DataStorage* dataStorage); + + const QString& GetWidgetName() const { return m_WidgetName; }; + QmitkRenderWindow* GetRenderWindow() const { return m_RenderWindow; }; + + mitk::SliceNavigationController* GetSliceNavigationController() const; + + void RequestUpdate(); + void ForceImmediateUpdate(); + + void SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower); + void ShowGradientBackground(bool enable); + std::pair GetGradientBackgroundColors() const { return m_GradientBackgroundColors; }; + bool IsGradientBackgroundOn() const; + + void SetDecorationColor(const mitk::Color& color); + mitk::Color GetDecorationColor() const { return m_DecorationColor; }; + + void ShowColoredRectangle(bool show); + bool IsColoredRectangleVisible() const; + + void ShowCornerAnnotation(bool show); + bool IsCornerAnnotationVisible() const; + void SetCornerAnnotationText(const std::string& cornerAnnotation); + std::string GetCornerAnnotationText() const; + + bool IsRenderWindowMenuActivated() const; + + void ActivateCrosshair(bool activate); + +private: + + void InitializeGUI(); + void InitializeDecorations(); + + void SetCrosshair(mitk::Point3D selectedPoint); + + QString m_WidgetName; + QHBoxLayout* m_Layout; + + mitk::DataStorage* m_DataStorage; + QmitkRenderWindow* m_RenderWindow; + + mitk::RenderingManager::Pointer m_RenderingManager; + mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; + + mitk::DataNode::Pointer m_PointSetNode; + mitk::PointSet::Pointer m_PointSet; + + std::pair m_GradientBackgroundColors; + mitk::Color m_DecorationColor; + vtkSmartPointer m_RectangleProp; + vtkSmartPointer m_CornerAnnotation; +}; + +#endif // QMITKRENDERWINDOWWIDGET_H diff --git a/Modules/QtWidgets/resource/Qmitk.qrc b/Modules/QtWidgets/resource/Qmitk.qrc index 2b4501588d..bc4fa4a99e 100644 --- a/Modules/QtWidgets/resource/Qmitk.qrc +++ b/Modules/QtWidgets/resource/Qmitk.qrc @@ -1,15 +1,18 @@ Binaerbilder_48.png Images_48.png PointSet_48.png Segmentation_48.png Surface_48.png mm_pointer.png mm_scroll.png mm_zoom.png mm_contrast.png mm_pan.png LabelSetImage_48.png + mwLayout.png + mwSynchronized.png + mwDesynchronized.png diff --git a/Modules/QtWidgets/resource/mwDesynchronized.png b/Modules/QtWidgets/resource/mwDesynchronized.png new file mode 100644 index 0000000000..81f087582c Binary files /dev/null and b/Modules/QtWidgets/resource/mwDesynchronized.png differ diff --git a/Modules/QtWidgets/resource/mwLayout.png b/Modules/QtWidgets/resource/mwLayout.png new file mode 100644 index 0000000000..e0e584a0e0 Binary files /dev/null and b/Modules/QtWidgets/resource/mwLayout.png differ diff --git a/Modules/QtWidgets/resource/mwSynchronized.png b/Modules/QtWidgets/resource/mwSynchronized.png new file mode 100644 index 0000000000..df4dd212ee Binary files /dev/null and b/Modules/QtWidgets/resource/mwSynchronized.png differ diff --git a/Modules/QtWidgets/resource/mwViewDirection.png b/Modules/QtWidgets/resource/mwViewDirection.png new file mode 100644 index 0000000000..880fab30d6 Binary files /dev/null and b/Modules/QtWidgets/resource/mwViewDirection.png differ diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp index 9afb4d48f6..7d16ab842f 100644 --- a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp @@ -1,115 +1,125 @@ /*=================================================================== 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 QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(QObject* parent/* = nullptr*/) : QAbstractItemModel(parent) , m_DataStorage(nullptr) , m_NodePredicate(nullptr) { // nothing here } QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent/* = nullptr*/) : QAbstractItemModel(parent) , m_DataStorage(nullptr) , m_NodePredicate(nullptr) { SetDataStorage(dataStorage); } QmitkAbstractDataStorageModel::~QmitkAbstractDataStorageModel() { if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listener from data storage dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); } } void QmitkAbstractDataStorageModel::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage == dataStorage) { return; } if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listener from old data storage dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); } m_DataStorage = dataStorage; if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkAbstractDataStorageModel::SetDataStorageDeleted); m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); // add listener for new data storage dataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); dataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); dataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); } // update model if the data storage has been changed DataStorageChanged(); } +mitk::DataStorage* QmitkAbstractDataStorageModel::GetDataStorage() const +{ + if (m_DataStorage.IsExpired()) + { + return nullptr; + } + + return m_DataStorage.Lock().GetPointer(); +} + void QmitkAbstractDataStorageModel::SetDataStorageDeleted() { this->SetDataStorage(nullptr); } void QmitkAbstractDataStorageModel::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate == nodePredicate) { return; } m_NodePredicate = nodePredicate; // update model if the node predicate has been changed NodePredicateChanged(); } diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp index a5d3182d1f..37e57944f5 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp @@ -1,61 +1,61 @@ /*=================================================================== 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 #include QmitkDataStorageListInspector::QmitkDataStorageListInspector(QWidget* parent/* = nullptr*/) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.view->setAlternatingRowColors(true); m_StorageModel = new QmitkDataStorageDefaultListModel(this); m_Controls.view->setModel(m_StorageModel); } QAbstractItemView* QmitkDataStorageListInspector::GetView() { return m_Controls.view; -}; +} const QAbstractItemView* QmitkDataStorageListInspector::GetView() const { return m_Controls.view; -}; +} void QmitkDataStorageListInspector::Initialize() { m_StorageModel->SetDataStorage(m_DataStorage.Lock()); m_StorageModel->SetNodePredicate(m_NodePredicate); m_Connector->SetView(m_Controls.view); } void QmitkDataStorageListInspector::SetSelectionMode(SelectionMode mode) { m_Controls.view->setSelectionMode(mode); } QmitkDataStorageListInspector::SelectionMode QmitkDataStorageListInspector::GetSelectionMode() const { return m_Controls.view->selectionMode(); -}; +} diff --git a/Modules/QtWidgets/src/QmitkInteractionSchemeToolBar.cpp b/Modules/QtWidgets/src/QmitkInteractionSchemeToolBar.cpp new file mode 100644 index 0000000000..98d34e39f5 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkInteractionSchemeToolBar.cpp @@ -0,0 +1,82 @@ +/*=================================================================== + +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 "QmitkInteractionSchemeToolBar.h" + +#include + +QmitkInteractionSchemeToolBar::QmitkInteractionSchemeToolBar(QWidget* parent/* = nullptr*/) + : QToolBar(parent) + , m_ActionGroup(new QActionGroup(this)) + , m_InteractionSchemeSwitcher(nullptr) + , m_InteractionEventHandler(nullptr) +{ + QToolBar::setOrientation(Qt::Vertical); + QToolBar::setIconSize(QSize(17, 17)); + m_ActionGroup->setExclusive(true); // only one selectable action + + AddButton(InteractionScheme::PACSStandard, tr("Pointer"), QIcon(":/Qmitk/mm_pointer.png"), true); + AddButton(InteractionScheme::PACSLevelWindow, tr("Level/Window"), QIcon(":/Qmitk/mm_contrast.png")); + AddButton(InteractionScheme::PACSPan, tr("Pan"), QIcon(":/Qmitk/mm_pan.png")); + AddButton(InteractionScheme::PACSScroll, tr("Scroll"), QIcon(":/Qmitk/mm_scroll.png")); + AddButton(InteractionScheme::PACSZoom, tr("Zoom"), QIcon(":/Qmitk/mm_zoom.png")); + + m_InteractionSchemeSwitcher = mitk::InteractionSchemeSwitcher::New(); +} + +void QmitkInteractionSchemeToolBar::SetInteractionEventHandler(mitk::InteractionEventHandler::Pointer interactionEventHandler) +{ + if (interactionEventHandler == m_InteractionEventHandler) + { + return; + } + + m_InteractionEventHandler = interactionEventHandler; + if (nullptr != m_InteractionEventHandler) + { + m_InteractionSchemeSwitcher->SetInteractionScheme(m_InteractionEventHandler, InteractionScheme::PACSStandard); + } +} + +void QmitkInteractionSchemeToolBar::AddButton(InteractionScheme interactionScheme, const QString& toolName, const QIcon& icon, bool on) +{ + QAction* action = new QAction(icon, toolName, this); + action->setCheckable(true); + action->setActionGroup(m_ActionGroup); + action->setChecked(on); + action->setData(interactionScheme); + connect(action, SIGNAL(triggered()), this, SLOT(OnInteractionSchemeChanged())); + QToolBar::addAction(action); +} + +QmitkInteractionSchemeToolBar::~QmitkInteractionSchemeToolBar() +{ + // nothing here +} + +void QmitkInteractionSchemeToolBar::OnInteractionSchemeChanged() +{ + QAction* action = dynamic_cast(sender()); + if (action) + { + InteractionScheme interactionScheme = static_cast(action->data().toInt()); + + if (m_InteractionEventHandler) + { + m_InteractionSchemeSwitcher->SetInteractionScheme(m_InteractionEventHandler, interactionScheme); + } + } +} diff --git a/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp b/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp index 3a909c39cd..b3b91efd71 100644 --- a/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp +++ b/Modules/QtWidgets/src/QmitkMouseModeSwitcher.cpp @@ -1,115 +1,112 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMouseModeSwitcher.h" #include -QmitkMouseModeSwitcher::QmitkMouseModeSwitcher(QWidget *parent) - : QToolBar(parent), - m_ActionGroup(new QActionGroup(this)), - m_MouseModeSwitcher(nullptr), - m_ObserverTag(0), - m_InObservationReaction(false) +QmitkMouseModeSwitcher::QmitkMouseModeSwitcher(QWidget* parent/* = nullptr*/) + : QToolBar(parent) + , m_ActionGroup(new QActionGroup(this)) + , m_MouseModeSwitcher(nullptr) + , m_ObserverTag(0) + , m_ActionButtonBlocked(false) { QToolBar::setOrientation(Qt::Vertical); QToolBar::setIconSize(QSize(17, 17)); - m_ActionGroup->setExclusive(true); // only one selectable + m_ActionGroup->setExclusive(true); // only one selectable action addButton(mitk::MouseModeSwitcher::MousePointer, tr("Pointer"), QIcon(":/Qmitk/mm_pointer.png"), true); // toggle ON addButton(mitk::MouseModeSwitcher::Scroll, tr("Scroll"), QIcon(":/Qmitk/mm_scroll.png")); addButton(mitk::MouseModeSwitcher::LevelWindow, tr("Level/Window"), QIcon(":/Qmitk/mm_contrast.png")); addButton(mitk::MouseModeSwitcher::Zoom, tr("Zoom"), QIcon(":/Qmitk/mm_zoom.png")); addButton(mitk::MouseModeSwitcher::Pan, tr("Pan"), QIcon(":/Qmitk/mm_pan.png")); } void QmitkMouseModeSwitcher::addButton(MouseMode id, const QString &toolName, const QIcon &icon, bool on) { - QAction *action = new QAction(icon, toolName, this); + QAction* action = new QAction(icon, toolName, this); action->setCheckable(true); action->setActionGroup(m_ActionGroup); action->setChecked(on); action->setData(id); - connect(action, SIGNAL(triggered()), this, SLOT(modeSelectedByUser())); + connect(action, SIGNAL(triggered()), this, SLOT(OnMouseModeChangedViaButton())); QToolBar::addAction(action); } QmitkMouseModeSwitcher::~QmitkMouseModeSwitcher() { - if (m_MouseModeSwitcher) + if (nullptr != m_MouseModeSwitcher) { m_MouseModeSwitcher->RemoveObserver(m_ObserverTag); } } void QmitkMouseModeSwitcher::setMouseModeSwitcher(mitk::MouseModeSwitcher *mms) { // goodbye / welcome ceremonies - if (m_MouseModeSwitcher) + if (nullptr != m_MouseModeSwitcher) { m_MouseModeSwitcher->RemoveObserver(m_ObserverTag); } m_MouseModeSwitcher = mms; if (m_MouseModeSwitcher) { - itk::ReceptorMemberCommand::Pointer command = - itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction(this, &QmitkMouseModeSwitcher::OnMouseModeChanged); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkMouseModeSwitcher::OnMouseModeChangedViaCommand); m_ObserverTag = m_MouseModeSwitcher->AddObserver(mitk::MouseModeSwitcher::MouseModeChangedEvent(), command); } } -void QmitkMouseModeSwitcher::modeSelectedByUser() +void QmitkMouseModeSwitcher::OnMouseModeChangedViaButton() { - if (m_InObservationReaction) - return; // this was NOT actually by the user but by ourselves - - QAction *action = dynamic_cast(sender()); + if (m_ActionButtonBlocked) + { + return; // blocked, since we change the checked state of the buttons in the callback function + } + QAction* action = dynamic_cast(sender()); if (action) { MouseMode id = static_cast(action->data().toInt()); // qDebug() << "Mouse mode '" << qPrintable(action->text()) << "' selected, trigger mode id " << id; if (m_MouseModeSwitcher) { m_MouseModeSwitcher->SetInteractionScheme(mitk::MouseModeSwitcher::InteractionScheme::PACS); m_MouseModeSwitcher->SelectMouseMode(id); } emit MouseModeSelected(id); } } -void QmitkMouseModeSwitcher::OnMouseModeChanged(const itk::EventObject &) +void QmitkMouseModeSwitcher::OnMouseModeChangedViaCommand(const itk::EventObject &) { - m_InObservationReaction = true; + m_ActionButtonBlocked = true; - // push button graphically assert(m_MouseModeSwitcher); - MouseMode activeMode = m_MouseModeSwitcher->GetCurrentMouseMode(); - - foreach (QAction *action, m_ActionGroup->actions()) + foreach(QAction* action, m_ActionGroup->actions()) { if (action->data().toInt() == activeMode) { action->setChecked(true); } } - m_InObservationReaction = false; + m_ActionButtonBlocked = false; } diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp new file mode 100644 index 0000000000..a078239b81 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp @@ -0,0 +1,82 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkMultiWidgetConfigurationToolBar.h" + +QmitkMultiWidgetConfigurationToolBar::QmitkMultiWidgetConfigurationToolBar() + : QToolBar() +{ + QToolBar::setOrientation(Qt::Vertical); + QToolBar::setIconSize(QSize(17, 17)); + + InitializeToolBar(); +} + +QmitkMultiWidgetConfigurationToolBar::~QmitkMultiWidgetConfigurationToolBar() +{ + // nothing here +} + +void QmitkMultiWidgetConfigurationToolBar::InitializeToolBar() +{ + // create popup to show a widget to modify the multi widget layout + m_LayoutSelectionPopup = new QmitkMultiWidgetLayoutSelectionWidget(this); + m_LayoutSelectionPopup->hide(); + + AddButtons(); + + connect(m_LayoutSelectionPopup, &QmitkMultiWidgetLayoutSelectionWidget::LayoutSet, this, &QmitkMultiWidgetConfigurationToolBar::LayoutSet); +} + +void QmitkMultiWidgetConfigurationToolBar::AddButtons() +{ + QAction* setLayoutAction = new QAction(QIcon(":/Qmitk/mwLayout.png"), tr("Set multi widget layout"), this); + connect(setLayoutAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSetLayout); + + QToolBar::addAction(setLayoutAction); + + m_SynchronizeAction = new QAction(QIcon(":/Qmitk/mwSynchronized.png"), tr("Desynchronize render windows"), this); + m_SynchronizeAction->setCheckable(true); + m_SynchronizeAction->setChecked(true); + connect(m_SynchronizeAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSynchronize); + + QToolBar::addAction(m_SynchronizeAction); +} + +void QmitkMultiWidgetConfigurationToolBar::OnSetLayout() +{ + m_LayoutSelectionPopup->setWindowFlags(Qt::Popup); + m_LayoutSelectionPopup->move(this->cursor().pos()); + m_LayoutSelectionPopup->show(); +} + +void QmitkMultiWidgetConfigurationToolBar::OnSynchronize() +{ + bool synchronized = m_SynchronizeAction->isChecked(); + if (synchronized) + { + m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwSynchronized.png")); + m_SynchronizeAction->setText(tr("Desynchronize render windows")); + } + else + { + m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwDesynchronized.png")); + m_SynchronizeAction->setText(tr("Synchronize render windows")); + } + + m_SynchronizeAction->setChecked(synchronized); + emit Synchronized(synchronized); +} diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp new file mode 100644 index 0000000000..687ad5a934 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp @@ -0,0 +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 "QmitkMultiWidgetLayoutSelectionWidget.h" + +QmitkMultiWidgetLayoutSelectionWidget::QmitkMultiWidgetLayoutSelectionWidget(QWidget* parent/* = 0*/) + : QWidget(parent) +{ + Init(); +} + +void QmitkMultiWidgetLayoutSelectionWidget::Init() +{ + ui.setupUi(this); + connect(ui.tableWidget, &QTableWidget::itemSelectionChanged, this, &QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged); + connect(ui.setLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked); +} + +void QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged() +{ + QItemSelectionModel* selectionModel = ui.tableWidget->selectionModel(); + + int row = 0; + int column = 0; + QModelIndexList indices = selectionModel->selectedIndexes(); + if (indices.size() > 0) + { + row = indices[0].row(); + column = indices[0].column(); + + QModelIndex topLeft = ui.tableWidget->model()->index(0, 0, QModelIndex()); + QModelIndex bottomRight = ui.tableWidget->model()->index(row, column, QModelIndex()); + + QItemSelection cellSelection; + cellSelection.select(topLeft, bottomRight); + selectionModel->select(cellSelection, QItemSelectionModel::Select); + } +} + +void QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked() +{ + int row = 0; + int column = 0; + QModelIndexList indices = ui.tableWidget->selectionModel()->selectedIndexes(); + if (indices.size() > 0) + { + // find largest row and column + for (const QModelIndex modelIndex : indices) + { + if (modelIndex.row() > row) + { + row = modelIndex.row(); + } + if (modelIndex.column() > column) + { + column = modelIndex.column(); + } + } + + close(); + emit LayoutSet(row+1, column+1); + } +} diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui new file mode 100644 index 0000000000..34d3e62dfd --- /dev/null +++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui @@ -0,0 +1,72 @@ + + + QmitkMultiWidgetLayoutSelectionWidget + + + + 0 + 0 + 230 + 230 + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + 3 + + + 4 + + + false + + + 50 + + + 50 + + + false + + + 50 + + + 50 + + + + + + + + + + + + + + + + Set multi widget layout + + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp new file mode 100644 index 0000000000..d206f56208 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp @@ -0,0 +1,431 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkMxNMultiWidget.h" + +#include +#include +#include +#include + +// mitk core +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// qt +#include + +QmitkMxNMultiWidget::QmitkMxNMultiWidget(QWidget* parent, + Qt::WindowFlags f/* = 0*/, + mitk::RenderingManager* renderingManager/* = nullptr*/, + mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/, + const QString& multiWidgetName/* = "mxnmulti"*/) + : QWidget(parent, f) + , m_MxNMultiWidgetLayout(nullptr) + , m_MultiWidgetRows(0) + , m_MultiWidgetColumns(0) + , m_PlaneMode(0) + , m_RenderingManager(renderingManager) + , m_RenderingMode(renderingMode) + , m_MultiWidgetName(multiWidgetName) + , m_DisplayActionEventBroadcast(nullptr) + , m_DisplayActionEventHandler(nullptr) + , m_DataStorage(nullptr) +{ + InitializeGUI(); + InitializeDisplayActionEventHandling(); + resize(QSize(364, 477).expandedTo(minimumSizeHint())); +} + +void QmitkMxNMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (dataStorage == m_DataStorage) + { + return; + } + + m_DataStorage = dataStorage; + // set new data storage for the render window widgets + for (const auto& renderWindowWidget : m_RenderWindowWidgets) + { + renderWindowWidget.second->SetDataStorage(m_DataStorage); + } +} + +void QmitkMxNMultiWidget::InitializeRenderWindowWidgets() +{ + m_MultiWidgetRows = 1; + m_MultiWidgetColumns = 1; + CreateRenderWindowWidget(); + InitializeGUI(); +} + +void QmitkMxNMultiWidget::ResetLayout(int row, int column) +{ + m_MultiWidgetRows = row; + m_MultiWidgetColumns = column; + + int requiredRenderWindowWidgets = m_MultiWidgetRows * m_MultiWidgetColumns; + int existingRenderWindowWidgets = m_RenderWindowWidgets.size(); + + int difference = requiredRenderWindowWidgets - existingRenderWindowWidgets; + while(0 < difference) + { + // more render window widgets needed + CreateRenderWindowWidget(); + --difference; + } + while(0 > difference) + { + // less render window widgets needed + DestroyRenderWindowWidget(); + ++difference; + } + + InitializeGUI(); +} + +void QmitkMxNMultiWidget::Synchronize(bool synchronized) +{ + auto allObserverTags = m_DisplayActionEventHandler->GetAllObserverTags(); + for (auto observerTag : allObserverTags) + { + m_DisplayActionEventHandler->DisconnectObserver(observerTag); + } + + if (synchronized) + { + mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); + } + else + { + mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveSenderCameraAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ZoomSenderCameraAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); + + actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); + } + + // use the standard 'set level window' action for both modes + mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::SetLevelWindowAction(); + m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetLevelWindowEvent(nullptr, mitk::ScalarType(), mitk::ScalarType()), actionFunction); +} + +QmitkMxNMultiWidget::RenderWindowWidgetMap QmitkMxNMultiWidget::GetRenderWindowWidgets() const +{ + return m_RenderWindowWidgets; +} + +QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetRenderWindowWidget(int row, int column) const +{ + return GetRenderWindowWidget(GetNameFromIndex(row, column)); +} + +QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetRenderWindowWidget(const QString& widgetName) const +{ + RenderWindowWidgetMap::const_iterator it = m_RenderWindowWidgets.find(widgetName); + if (it != m_RenderWindowWidgets.end()) + { + return it->second; + } + + return nullptr; +} + +QmitkMxNMultiWidget::RenderWindowHash QmitkMxNMultiWidget::GetRenderWindows() const +{ + RenderWindowHash result; + // create QHash on demand + auto renderWindowWidgets = GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); + } + + return result; +} + +QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(int row, int column) const +{ + return GetRenderWindow(GetNameFromIndex(row, column)); +} + +QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const QString& widgetName) const +{ + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->GetRenderWindow(); + } + + return nullptr; +} + +void QmitkMxNMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) +{ + m_ActiveRenderWindowWidget = activeRenderWindowWidget; +} + +QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetActiveRenderWindowWidget() const +{ + return m_ActiveRenderWindowWidget; +} + +QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetFirstRenderWindowWidget() const +{ + if (!m_RenderWindowWidgets.empty()) + { + return m_RenderWindowWidgets.begin()->second; + } + else + { + return nullptr; + } +} + +QmitkMxNMultiWidget::RenderWindowWidgetPointer QmitkMxNMultiWidget::GetLastRenderWindowWidget() const +{ + if (!m_RenderWindowWidgets.empty()) + { + return m_RenderWindowWidgets.rbegin()->second; + } + else + { + return nullptr; + } +} + +unsigned int QmitkMxNMultiWidget::GetNumberOfRenderWindowWidgets() const +{ + return m_RenderWindowWidgets.size(); +} + +void QmitkMxNMultiWidget::RequestUpdate(const QString& widgetName) +{ + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->RequestUpdate(); + } +} + +void QmitkMxNMultiWidget::RequestUpdateAll() +{ + for (const auto& renderWindowWidget : m_RenderWindowWidgets) + { + renderWindowWidget.second->RequestUpdate(); + } +} + +void QmitkMxNMultiWidget::ForceImmediateUpdate(const QString& widgetName) +{ + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->ForceImmediateUpdate(); + } +} + +void QmitkMxNMultiWidget::ForceImmediateUpdateAll() +{ + for (const auto& renderWindowWidget : m_RenderWindowWidgets) + { + renderWindowWidget.second->ForceImmediateUpdate(); + } +} + +void QmitkMxNMultiWidget::ActivateAllCrosshairs(bool activate) +{ + for (const auto& renderWindowWidget : m_RenderWindowWidgets) + { + renderWindowWidget.second->ActivateCrosshair(activate); + } +} + +const mitk::Point3D QmitkMxNMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const +{ + // see T26208 + return mitk::Point3D(); +} + +////////////////////////////////////////////////////////////////////////// +// PUBLIC SLOTS +////////////////////////////////////////////////////////////////////////// +void QmitkMxNMultiWidget::SetSelectedPosition(const QString& widgetName, const mitk::Point3D& newPosition) +{ + RenderWindowWidgetPointer renderWindowWidget; + if (widgetName.isNull()) + { + renderWindowWidget = GetActiveRenderWindowWidget(); + } + else + { + renderWindowWidget = GetRenderWindowWidget(widgetName); + } + + if (nullptr != renderWindowWidget) + { + renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); + renderWindowWidget->RequestUpdate(); + return; + } + + MITK_ERROR << "Position can not be set for an unknown render window widget."; +} + +////////////////////////////////////////////////////////////////////////// +// MOUSE EVENTS +////////////////////////////////////////////////////////////////////////// +void QmitkMxNMultiWidget::wheelEvent(QWheelEvent* e) +{ + emit WheelMoved(e); +} + +void QmitkMxNMultiWidget::mousePressEvent(QMouseEvent* /*e*/) +{ +} + +void QmitkMxNMultiWidget::moveEvent(QMoveEvent* e) +{ + QWidget::moveEvent(e); + + // it is necessary to readjust the position of the overlays as the MultiWidget has moved + // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here + emit Moved(); +} + +////////////////////////////////////////////////////////////////////////// +// PRIVATE +////////////////////////////////////////////////////////////////////////// +void QmitkMxNMultiWidget::InitializeGUI() +{ + delete m_MxNMultiWidgetLayout; + m_MxNMultiWidgetLayout = new QGridLayout(this); + m_MxNMultiWidgetLayout->setContentsMargins(0, 0, 0, 0); + setLayout(m_MxNMultiWidgetLayout); + + FillMultiWidgetLayout(); +} + +void QmitkMxNMultiWidget::InitializeDisplayActionEventHandling() +{ + m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); + m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); + m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigPACS.xml"); + + m_DisplayActionEventHandler = std::make_unique(); + m_DisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); + + Synchronize(true); +} + +void QmitkMxNMultiWidget::CreateRenderWindowWidget() +{ + // create the render window widget and connect signals / slots + QString renderWindowWidgetName = GetNameFromIndex(m_RenderWindowWidgets.size()); + RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, m_DataStorage); + renderWindowWidget->SetCornerAnnotationText(renderWindowWidgetName.toStdString()); + + // store the newly created render window widget with the UID + m_RenderWindowWidgets.insert(std::make_pair(renderWindowWidgetName, renderWindowWidget)); +} + +void QmitkMxNMultiWidget::DestroyRenderWindowWidget() +{ + auto iterator = m_RenderWindowWidgets.find(GetNameFromIndex(m_RenderWindowWidgets.size() - 1)); + if (iterator == m_RenderWindowWidgets.end()) + { + return; + } + + // disconnect each signal of this render window widget + RenderWindowWidgetPointer renderWindowWidgetToRemove = iterator->second; + disconnect(renderWindowWidgetToRemove.get(), 0, 0, 0); + + // erase the render window from the map + m_RenderWindowWidgets.erase(iterator); +} + +void QmitkMxNMultiWidget::FillMultiWidgetLayout() +{ + for (int row = 0; row < m_MultiWidgetRows; ++row) + { + for (int column = 0; column < m_MultiWidgetColumns; ++column) + { + RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(row, column); + if (nullptr != renderWindowWidget) + { + m_MxNMultiWidgetLayout->addWidget(renderWindowWidget.get(), row, column); + SetActiveRenderWindowWidget(renderWindowWidget); + } + } + } +} + +QString QmitkMxNMultiWidget::GetNameFromIndex(int row, int column) const +{ + if (0 <= row && m_MultiWidgetRows > row && 0 <= column && m_MultiWidgetColumns > column) + { + return GetNameFromIndex(row * m_MultiWidgetColumns + column); + } + + return QString(); +} + +QString QmitkMxNMultiWidget::GetNameFromIndex(size_t index) const +{ + if (index <= m_RenderWindowWidgets.size()) + { + return m_MultiWidgetName + ".widget" + QString::number(index); + } + + return QString(); +} diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp new file mode 100644 index 0000000000..f607f51ab4 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -0,0 +1,250 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkRenderWindowWidget.h" + +// mitk qt widgets +#include + +// vtk +#include + +QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, + const QString& widgetName/* = ""*/, + mitk::DataStorage* dataStorage/* = nullptr*/, + mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::Standard*/) + : QWidget(parent) + , m_WidgetName(widgetName) + , m_DataStorage(dataStorage) + , m_RenderWindow(nullptr) + , m_RenderingMode(renderingMode) + , m_PointSetNode(nullptr) + , m_PointSet(nullptr) +{ + InitializeGUI(); +} + +QmitkRenderWindowWidget::~QmitkRenderWindowWidget() +{ + auto sliceNavigationController = m_RenderWindow->GetSliceNavigationController(); + if (nullptr != sliceNavigationController) + { + sliceNavigationController->SetCrosshairEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); + } + if (nullptr != m_DataStorage) + { + m_DataStorage->Remove(m_PointSetNode); + } +} + +void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (dataStorage == m_DataStorage) + { + return; + } + + m_DataStorage = dataStorage; + if (nullptr != m_RenderWindow) + { + mitk::BaseRenderer::GetInstance(m_RenderWindow->GetRenderWindow())->SetDataStorage(dataStorage); + } +} + +mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const +{ + return m_RenderWindow->GetSliceNavigationController(); +} + +void QmitkRenderWindowWidget::RequestUpdate() +{ + m_RenderingManager->RequestUpdate(m_RenderWindow->GetRenderWindow()); +} + +void QmitkRenderWindowWidget::ForceImmediateUpdate() +{ + m_RenderingManager->ForceImmediateUpdate(m_RenderWindow->GetRenderWindow()); +} + +void QmitkRenderWindowWidget::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) +{ + vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); + if (nullptr == vtkRenderer) + { + return; + } + + m_GradientBackgroundColors.first = upper; + m_GradientBackgroundColors.second = lower; + vtkRenderer->SetBackground(lower[0], lower[1], lower[2]); + vtkRenderer->SetBackground2(upper[0], upper[1], upper[2]); + + ShowGradientBackground(true); +} + +void QmitkRenderWindowWidget::ShowGradientBackground(bool show) +{ + m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetGradientBackground(show); +} + +bool QmitkRenderWindowWidget::IsGradientBackgroundOn() const +{ + return m_RenderWindow->GetRenderer()->GetVtkRenderer()->GetGradientBackground(); +} + +void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) +{ + m_DecorationColor = color; + m_RectangleProp->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); + m_CornerAnnotation->GetTextProperty()->SetColor(color[0], color[1], color[2]); +} + +void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) +{ + m_RectangleProp->SetVisibility(show); +} + +bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const +{ + return m_RectangleProp->GetVisibility() > 0; +} + +void QmitkRenderWindowWidget::ShowCornerAnnotation(bool show) +{ + m_CornerAnnotation->SetVisibility(show); +} + +bool QmitkRenderWindowWidget::IsCornerAnnotationVisible() const +{ + return m_CornerAnnotation->GetVisibility() > 0; +} + +void QmitkRenderWindowWidget::SetCornerAnnotationText(const std::string& cornerAnnotation) +{ + m_CornerAnnotation->SetText(0, cornerAnnotation.c_str()); +} + +std::string QmitkRenderWindowWidget::GetCornerAnnotationText() const +{ + return std::string(m_CornerAnnotation->GetText(0)); +} + +bool QmitkRenderWindowWidget::IsRenderWindowMenuActivated() const +{ + return m_RenderWindow->GetActivateMenuWidgetFlag(); +} + +void QmitkRenderWindowWidget::ActivateCrosshair(bool activate) +{ + if (nullptr == m_DataStorage) + { + return; + } + + if (activate) + { + try + { + m_DataStorage->Add(m_PointSetNode); + } + catch(std::invalid_argument& /*e*/) + { + // crosshair already existing + return; + } + } + else + { + m_DataStorage->Remove(m_PointSetNode); + } +} + +void QmitkRenderWindowWidget::InitializeGUI() +{ + m_Layout = new QHBoxLayout(this); + m_Layout->setMargin(0); + setLayout(m_Layout); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + // create render window for this render window widget + m_RenderingManager = mitk::RenderingManager::GetInstance(); + //m_RenderingManager = mitk::RenderingManager::New(); + m_RenderingManager->SetDataStorage(m_DataStorage); + + m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr, m_RenderingManager, m_RenderingMode); + m_RenderWindow->SetLayoutIndex(mitk::SliceNavigationController::Sagittal); + m_RenderWindow->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderWindow->GetSliceNavigationController()->SetRenderingManager(m_RenderingManager); + m_RenderWindow->GetSliceNavigationController()->SetCrosshairEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); + + mitk::TimeGeometry::ConstPointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); + m_RenderingManager->InitializeViews(timeGeometry); + m_Layout->addWidget(m_RenderWindow); + + // add point set as a crosshair + m_PointSetNode = mitk::DataNode::New(); + m_PointSetNode->SetProperty("name", mitk::StringProperty::New("Crosshair of render window " + m_WidgetName.toStdString())); + m_PointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); // crosshair-node should typically be invisible + + // set the crosshair only visible for this specific renderer + m_PointSetNode->SetBoolProperty("fixedLayer", true, m_RenderWindow->GetRenderer()); + m_PointSetNode->SetVisibility(true, m_RenderWindow->GetRenderer()); + m_PointSetNode->SetVisibility(false); + + m_PointSet = mitk::PointSet::New(); + m_PointSetNode->SetData(m_PointSet); + + // set colors and corner annotation + InitializeDecorations(); +} + +void QmitkRenderWindowWidget::InitializeDecorations() +{ + vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); + if (nullptr == vtkRenderer) + { + return; + } + + // initialize background color gradients + float black[3] = { 0.0f, 0.0f, 0.0f }; + SetGradientBackgroundColors(black, black); + + // initialize decoration color, rectangle and annotation text + float white[3] = { 1.0f, 1.0f, 1.0f }; + m_DecorationColor = white; + m_RectangleProp = vtkSmartPointer::New(); + m_RectangleProp->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); + if (0 == vtkRenderer->HasViewProp(m_RectangleProp)) + { + vtkRenderer->AddViewProp(m_RectangleProp); + } + + m_CornerAnnotation = vtkSmartPointer::New(); + m_CornerAnnotation->SetText(0, "Sagittal"); + m_CornerAnnotation->SetMaximumFontSize(12); + m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); + if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) + { + vtkRenderer->AddViewProp(m_CornerAnnotation); + } +} + +void QmitkRenderWindowWidget::SetCrosshair(mitk::Point3D selectedPoint) +{ + m_PointSet->SetPoint(1, selectedPoint, 0); + mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); +} diff --git a/Modules/RenderWindowManager/CMakeLists.txt b/Modules/RenderWindowManager/CMakeLists.txt index 2b876f73bc..f2a2a480bc 100644 --- a/Modules/RenderWindowManager/CMakeLists.txt +++ b/Modules/RenderWindowManager/CMakeLists.txt @@ -1,5 +1,3 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS Qmitk - DEPENDS MitkQtWidgets - PACKAGE_DEPENDS PUBLIC CTK Qt5|Core + DEPENDS MitkCore ) diff --git a/Modules/RenderWindowManager/include/mitkRenderWindowLayerController.h b/Modules/RenderWindowManager/include/mitkRenderWindowLayerController.h index 9000f6f6d3..d81a6bf2e7 100644 --- a/Modules/RenderWindowManager/include/mitkRenderWindowLayerController.h +++ b/Modules/RenderWindowManager/include/mitkRenderWindowLayerController.h @@ -1,169 +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 MITKRENDERWINDOWLAYERCONTROLLER_H #define MITKRENDERWINDOWLAYERCONTROLLER_H // render window manager module #include "MitkRenderWindowManagerExports.h" #include "mitkRenderWindowLayerUtilities.h" // mitk core #include #include #include namespace mitk { /** * The RenderWindowLayerController is used to manipulate the 'layer', 'fixedLayer' and 'visible' property of a given data node. * The 'layer' property is used to denote the layer level of a data node. Data from nodes on higher layer level are rendered * on top of data from nodes on lower layer level. It can be changed using the 'MoveNode*'-functions. * * To view the data of a data node only in a specific renderer, the "InsertLayerNode'-function should be used. It inserts the * given node into the specified renderer and sets the corresponding properties. * To hide the data in the common renderer view (all renderer), the 'HideDataNodeInAllRenderer'-function can be used. * Inserting and showing a data node in a specific renderer / render window, will overwrite the properties of the common renderer view. * * For more information about the data node properties for specific renderer, see mitk::DataNode- and mitk::PropertyList-classes. * * Functions with 'mitk::BaseRenderer* renderer' have 'nullptr' as their default argument. Using the nullptr * these functions operate on all base renderer. Giving a specific base renderer will modify the node only for the given renderer. */ class MITKRENDERWINDOWMANAGER_EXPORT RenderWindowLayerController { public: RenderWindowLayerController(); /** * @brief Set the data storage on which to work. */ void SetDataStorage(DataStorage::Pointer dataStorage); /** * @brief Set the controlled base renderer. */ void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); // wrapper functions to modify the layer order / visibility of render window data /** * @brief Set the given node as the base node of the given renderer. * * @param dataNode The data node whose layer is to be modified. * @param renderer Pointer to the renderer instance for which the data node property should be modified. * If it is a nullptr (default) all controlled renderer will be affected. */ void SetBaseDataNode(DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** * @brief Insert the given data node at the specified layer for the given renderer. * * @param dataNode The data node that should be inserted. * @param layer The layer value for the "layer" property of the data node (insertion level). "layer = RenderWindowLayerUtilities::TOP_LAYER_INDEX" (default) inserts the given data node at the top of the node stack (topmost layer). * @param renderer Pointer to the renderer instance for which the data node should be inserted. * If it is a nullptr (default) all controlled renderer will be affected. * * @post After a successful call, the "fixedLayer" and "visibility" property will be true and the "layer" property will be set correctly. */ void InsertLayerNode(DataNode* dataNode, int layer = RenderWindowLayerUtilities::TOP_LAYER_INDEX, const BaseRenderer* renderer = nullptr); /** * @brief Remove the given data node for the given renderer. * * @param dataNode The data node that should be removed. * @param renderer Pointer to the renderer instance for which the data node should be removed. * If it is a nullptr (default) all controlled renderer will be affected. * * @post After a successful call, the "fixedLayer" and "visibility" property will be false and the "layer" property will be deleted. */ void RemoveLayerNode(DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** + * @brief Move the data node to the given layer. This will change only the "layer" property. + * + * @param dataNode The data node that should be moved. + * @param renderer Pointer to the renderer instance for which the data node should be moved. + * If it is a nullptr (default) all controlled renderer will be affected. + */ + bool MoveNodeToPosition(DataNode* dataNode, int newLayer, const BaseRenderer* renderer = nullptr); + /** * @brief Set the node in the given renderer as the topmost layer. This will change only the "layer" property. * * @param dataNode The data node that should be moved. * @param renderer Pointer to the renderer instance for which the data node should be moved. * If it is a nullptr (default) all controlled renderer will be affected. */ bool MoveNodeToFront(DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** * @brief Set the node in the given renderer as the lowermost layer. This will change only the "layer" property. * * @param dataNode The data node that should be moved. * @param renderer Pointer to the renderer instance for which the data node should be moved. * If it is a nullptr (default) all controlled renderer will be affected. */ bool MoveNodeToBack(DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** * @brief Move the node in the given renderer one layer down. This will change only the "layer" property. * * @param dataNode The data node that should be moved. * @param renderer Pointer to the renderer instance for which the data node should be moved. * If it is a nullptr (default) all controlled renderer will be affected. */ bool MoveNodeUp(DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** * @brief Move the node in the given renderer one layer up. This will change only the "layer" property. * * @param dataNode The data node that should be moved. * @param renderer Pointer to the renderer instance for which the data node should be moved. * If it is a nullptr (default) all controlled renderer will be affected. */ bool MoveNodeDown(DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** * @brief Set the visibility of the given data node for the given renderer. * * @param visibility Boolean to set the "visible" property of the given data node. * @param dataNode The data node that should be moved. * @param renderer Pointer to the renderer instance for which the data node should be modified. * If it is a nullptr (default) all controlled renderer will be affected. * * @post After a successful call , the "visibility" property will be set to the "visibility" value. */ void SetVisibilityOfDataNode(bool visiblity, DataNode* dataNode, const BaseRenderer* renderer = nullptr); /** * @brief Hide the given data node by setting the "visible" property of the data node for * all controlled renderer to false. * Later setting the "visible" property of the data node for a certain renderer will overwrite * the same property of the common renderer. * * @param dataNode The data node that should be hid. * * @post After a successful call , the "visibility" property will be set to the false. */ void HideDataNodeInAllRenderer(const DataNode* dataNode); /** * @brief Reset the given render window: * If "onlyVisibility = true": set all data nodes for the given render window to invisible, except for the base node. * If "onlyVisibility = false": remove all data nodes from the render window, except for the base node. * * @param visibility Boolean to define the reset mode. * @param renderer Pointer to the renderer instance for which the data node should be reset. * If it is a nullptr (default) all controlled renderer will be affected. * * @post After a successful call , the "visibility" property will be set to the "false" value (except for the base node). * If "onlyVisibility = false": additionally the "fixedLayer" property will be false and the "layer" property will be deleted. */ void ResetRenderer(bool onlyVisibility = true, const BaseRenderer* renderer = nullptr); private: void InsertLayerNodeInternal(DataNode* dataNode, int layer, const BaseRenderer* renderer = nullptr); DataStorage::Pointer m_DataStorage; RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; }; } // namespace mitk #endif // MITKRENDERWINDOWLAYERCONTROLLER_H diff --git a/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h b/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h index e119c43c10..6e30a38584 100644 --- a/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h +++ b/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h @@ -1,61 +1,71 @@ /*=================================================================== 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 MITKRENDERWINDOWLAYERUTILITIES_H #define MITKRENDERWINDOWLAYERUTILITIES_H // render window manager module #include "MitkRenderWindowManagerExports.h" // mitk core #include #include #include +#include /** * @brief Render window layer helper functions to retrieve the currently valid layer stack */ -namespace RenderWindowLayerUtilities +namespace mitk { - typedef std::vector RendererVector; - typedef std::map> LayerStack; - - /** - * The base data node of a renderer is supposed to be on layer 0 (zero), which should be the lowest layer in a render window. - */ - const int BASE_LAYER_INDEX = 0; - /** - * The top layer index, denoting that no valid (positive) layer index is given and therefore the index should be resolved into the topmost layer index. - */ - const int TOP_LAYER_INDEX = -1; - - /** - * @brief Return the stack of layers of the given renderer as std::map, which guarantees ordering of the layers. - * Stacked layers are only included if they have their "fixedLayer" property set to true and their "layer" property set. - * - * If "renderer" = nullptr: a layer stack won't be created and an empty "LayerStack" will be returned. - * If "withBaseNode" = true: include the base node in the layer stack, if existing. - * If "withBaseNode" = false: exclude the base node from the layer stack. - * - * @param dataStorage Pointer to a data storage instance whose data nodes should be checked and possibly be included. - * @param renderer Pointer to the renderer instance for which the layer stack should be generated. - * @param withBaseNode Boolean to decide whether the base node should be included in or excluded from the layer stack. - */ - MITKRENDERWINDOWMANAGER_EXPORT LayerStack GetLayerStack(const mitk::DataStorage* dataStorage, const mitk::BaseRenderer* renderer, bool withBaseNode); - -} // namespace RenderWindowLayerUtilities + namespace RenderWindowLayerUtilities + { + typedef std::vector RendererVector; + typedef std::map> LayerStack; + + /** + * The base data node of a renderer is supposed to be on layer 0 (zero), which should be the lowest layer in a render window. + */ + const int BASE_LAYER_INDEX = 0; + /** + * The top layer index, denoting that no valid (positive) layer index is given and therefore the index should be resolved into the topmost layer index. + */ + const int TOP_LAYER_INDEX = -1; + + /** + * @brief Return the stack of layers of the given renderer as std::map, which guarantees ordering of the layers. + * Stacked layers are only included if they have their "fixedLayer" property set to true and their "layer" property set. + * + * If "renderer" = nullptr: a layer stack won't be created and an empty "LayerStack" will be returned. + * If "withBaseNode" = true: include the base node in the layer stack, if existing. + * If "withBaseNode" = false: exclude the base node from the layer stack. + * + * @param dataStorage Pointer to a data storage instance whose data nodes should be checked and possibly be included. + * @param renderer Pointer to the renderer instance for which the layer stack should be generated. + * @param withBaseNode Boolean to decide whether the base node should be included in or excluded from the layer stack. + */ + MITKRENDERWINDOWMANAGER_EXPORT LayerStack GetLayerStack(const DataStorage* dataStorage, const BaseRenderer* renderer, bool withBaseNode); + /** + * @brief Helper function to get a node predicate that can be used to filter render window specific data nodes. + * + * The data nodes must not be 'helper objects'. The must have set a 'fixed layer' property for the given renderer. + */ + MITKRENDERWINDOWMANAGER_EXPORT NodePredicateAnd::Pointer GetRenderWindowPredicate(const BaseRenderer* renderer); + + } // namespace RenderWindowLayerUtilities +} // namespace mitk #endif // MITKRENDERWINDOWLAYERUTILITIES_H diff --git a/Modules/RenderWindowManager/include/mitkRenderWindowViewDirectionController.h b/Modules/RenderWindowManager/include/mitkRenderWindowViewDirectionController.h index 40752c35d4..9280a6df77 100644 --- a/Modules/RenderWindowManager/include/mitkRenderWindowViewDirectionController.h +++ b/Modules/RenderWindowManager/include/mitkRenderWindowViewDirectionController.h @@ -1,74 +1,86 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKRENDERWINDOWVIEWDIRECTIONCONTROLLER_H #define MITKRENDERWINDOWVIEWDIRECTIONCONTROLLER_H // render window manager module #include "MitkRenderWindowManagerExports.h" #include "mitkRenderWindowLayerUtilities.h" // mitk core #include #include namespace mitk { /** * The RenderWindowViewDirectionController is used to manipulate the 'sliceNavigationController' of a given base renderer. * The 'sliceNavigationController' is used to set the view direction / camera perspective of a base renderer. * The view direction can changed to 'mitk::SliceNavigationController::Axial', 'mitk::SliceNavigationController::Frontal' * or 'mitk::SliceNavigationController::Sagittal'. * * Functions with 'mitk::BaseRenderer* renderer' have 'nullptr' as their default argument. Using the nullptr - * these functions operate on all base renderer. Giving a specific base renderer will modify the node only for the given renderer. + * these functions operate on all base renderer. Giving a specific base renderer will modify the view direction only for the given renderer. */ class MITKRENDERWINDOWMANAGER_EXPORT RenderWindowViewDirectionController { public: + using ViewDirection = mitk::SliceNavigationController::ViewDirection; + RenderWindowViewDirectionController(); /** * @brief Set the data storage on which to work. */ void SetDataStorage(DataStorage::Pointer dataStorage); /** * @brief Set the controlled base renderer. */ void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); // wrapper functions to modify the view direction /** * @brief Set the view direction for the given renderer (nullptr = all renderer) - * @param viewDirection The view direction that should be used for this renderer. + * @param viewDirection The view direction that should be used for this renderer as a string. * Currently "axial", "coronal" and "sagittal" is supported. * @param renderer Pointer to the renderer instance for which the view direction should be changed. - * If it is a nullptr (default) nothing happens. The view direction can not be changed - * for all controlled renderer at the moment. + * If it is a nullptr (default) all controlled renderer will be affected. + */ + void SetViewDirectionOfRenderer(const std::string& viewDirection, BaseRenderer* renderer = nullptr); + /** + * @brief Set the view direction for the given renderer (nullptr = all renderer) + * @param viewDirection The view direction that should be used for this renderer. + * @param renderer Pointer to the renderer instance for which the view direction should be changed. + * If it is a nullptr (default) nothing happens. */ - void SetViewDirectionOfRenderer(const std::string &viewDirection, BaseRenderer* renderer = nullptr); + void SetViewDirectionOfRenderer(ViewDirection viewDirection, BaseRenderer* renderer = nullptr); + /** + * @brief Reinitialize the given renderer with the currently visible nodes. + * @param renderer Pointer to the renderer instance for which the view direction should be changed. + * If it is a nullptr (default) all controlled renderer will be affected. + */ + void InitializeViewByBoundingObjects(const BaseRenderer* renderer); private: - void InitializeViewByBoundingObjects(const BaseRenderer* renderer); - DataStorage::Pointer m_DataStorage; RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; }; } // namespace mitk #endif // MITKRENDERWINDOWVIEWDIRECTIONCONTROLLER_H diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp index 7f47606503..2ba1043c82 100644 --- a/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp +++ b/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp @@ -1,500 +1,575 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager module #include "mitkRenderWindowLayerController.h" mitk::RenderWindowLayerController::RenderWindowLayerController() : m_DataStorage(nullptr) { // nothing here } void mitk::RenderWindowLayerController::SetDataStorage(DataStorage::Pointer dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage m_DataStorage = dataStorage; } } void mitk::RenderWindowLayerController::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { if (m_ControlledRenderer != controlledRenderer) { // set the new set of controlled renderer m_ControlledRenderer = controlledRenderer; } } void mitk::RenderWindowLayerController::SetBaseDataNode(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // set the data node as base data node in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { SetBaseDataNode(dataNode, renderer); } } } else { // get the layer stack with the base data node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, true); if (!stackedLayers.empty()) { // see if base layer exists RenderWindowLayerUtilities::LayerStack::iterator layerStackIterator = stackedLayers.find(RenderWindowLayerUtilities::BASE_LAYER_INDEX); if (layerStackIterator != stackedLayers.end()) { // remove the current base data node from the current renderer layerStackIterator->second->GetPropertyList(renderer)->DeleteProperty("layer"); layerStackIterator->second->SetBoolProperty("fixedLayer", false, renderer); layerStackIterator->second->SetVisibility(false, renderer); } } // "RenderWindowLayerUtilities::BASE_LAYER_INDEX" indicates the base data node --> set as new background dataNode->SetIntProperty("layer", RenderWindowLayerUtilities::BASE_LAYER_INDEX, renderer); dataNode->SetBoolProperty("fixedLayer", true, renderer); dataNode->SetVisibility(true, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } void mitk::RenderWindowLayerController::InsertLayerNode(DataNode* dataNode, int layer /*= RenderWindowLayerUtilities::TOP_LAYER_INDEX*/, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // insert data node in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { InsertLayerNode(dataNode, layer, renderer); } } } else { if (RenderWindowLayerUtilities::BASE_LAYER_INDEX == layer) { // "RenderWindowLayerUtilities::BASE_LAYER_INDEX" indicates the base data node --> set as new background (overwrite current base node if needed) SetBaseDataNode(dataNode, renderer); } else { InsertLayerNodeInternal(dataNode, layer, renderer); } } } void mitk::RenderWindowLayerController::InsertLayerNodeInternal(DataNode* dataNode, int newLayer, const BaseRenderer* renderer /*= nullptr*/) { dataNode->SetBoolProperty("fixedLayer", true, renderer); - dataNode->SetVisibility(true, renderer); + // use visibility of existing renderer or common renderer + bool visible = false; + bool visibilityProperty = dataNode->GetVisibility(visible, renderer); + if (true == visibilityProperty) + { + // found a visibility property + dataNode->SetVisibility(visible, renderer); + } // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (stackedLayers.empty()) { // no layer stack for the current renderer if (RenderWindowLayerUtilities::TOP_LAYER_INDEX == newLayer) { // set given layer as first layer above base layer (= 1) newLayer = 1; // alternatively: no layer stack for the current renderer -> insert as background node //SetBaseDataNode(dataNode, renderer); } } else { if (RenderWindowLayerUtilities::TOP_LAYER_INDEX == newLayer) { // get the first value (highest int-key -> topmost layer) - // +1 indicates inserting the node above the topmost layer + // + 1 indicates inserting the node above the topmost layer newLayer = stackedLayers.begin()->first + 1; } else { - // see if layer is already taken - RenderWindowLayerUtilities::LayerStack::iterator layerStackIterator = stackedLayers.find(newLayer); - for (; layerStackIterator != stackedLayers.end(); ++layerStackIterator) - { - // move data nodes after the new layer one layer up - layerStackIterator->second->SetIntProperty("layer", layerStackIterator->first + 1, renderer); - } + MoveNodeToPosition(dataNode, newLayer, renderer); + return; } } // update data storage (the "data node model") dataNode->SetIntProperty("layer", newLayer, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } void mitk::RenderWindowLayerController::RemoveLayerNode(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // remove data node from all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { RemoveLayerNode(dataNode, renderer); } } } else { // "remove" node from the renderer list dataNode->GetPropertyList(renderer)->DeleteProperty("layer"); dataNode->SetBoolProperty("fixedLayer", false, renderer); dataNode->SetVisibility(false, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } +bool mitk::RenderWindowLayerController::MoveNodeToPosition(DataNode* dataNode, int newLayer, const BaseRenderer* renderer /*= nullptr*/) +{ + if (nullptr == dataNode) + { + return false; + } + + if (nullptr == renderer) + { + // move data node to position in all controlled renderer + for (const auto& renderer : m_ControlledRenderer) + { + if (nullptr != renderer) + { + MoveNodeToPosition(dataNode, newLayer, renderer); + // we don't store/need the returned boolean value + return false; + } + } + } + else + { + // get the layer stack without the base node of the current renderer + RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); + if (!stackedLayers.empty()) + { + // get the current layer value of the given data node + int currentLayer; + bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); + if (wasFound && currentLayer != newLayer) + { + // move the given data node to the specified layer + dataNode->SetIntProperty("layer", newLayer, renderer); + + int upperBound; + int lowerBound; + int step; + if (currentLayer < newLayer) + { + // move node up + upperBound = newLayer + 1; + lowerBound = currentLayer + 1; + step = -1; // move all other nodes one step down + } + else + { + upperBound = currentLayer; + lowerBound = newLayer; + step = 1; // move all other nodes one step up + } + + // move all other data nodes between the upper and the lower bound + for (auto& layer : stackedLayers) + { + if (layer.second != dataNode && layer.first < upperBound && layer.first >= lowerBound) + { + layer.second->SetIntProperty("layer", layer.first + step, renderer); + } + // else: current data node is the selected data node or + // was previously already above the selected data node or + // was previously already below the new layer position + } + dataNode->Modified(); + mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); + return true; + } + // else: data node has no layer information or is already at the specified position + } + // else: do not work with empty layer stack + } + return false; +} + bool mitk::RenderWindowLayerController::MoveNodeToFront(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node to front in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { MoveNodeToFront(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the first value (highest int-key -> topmost layer) int topmostLayer = stackedLayers.begin()->first; // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound && currentLayer < topmostLayer) { // move the current data node above the current topmost layer dataNode->SetIntProperty("layer", topmostLayer+1, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node has no layer information or is already the topmost layer node } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeToBack(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node to back in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { MoveNodeToBack(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the last value (lowest int-key) // cannot be the base layer as the base node was excluded by the 'GetLayerStack'-function int lowermostLayer = stackedLayers.rbegin()->first; // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound && currentLayer > lowermostLayer) { // move the current data node to the current lowermost layer dataNode->SetIntProperty("layer", lowermostLayer, renderer); // move all other data nodes one layer up for (auto& layer : stackedLayers) { if (layer.second != dataNode && layer.first < currentLayer) { layer.second->SetIntProperty("layer", layer.first + 1, renderer); } // else: current data node is the selected data node or // was previously already above the selected data node } dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node has no layer information or is already the lowermost layer node } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeUp(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node down in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { MoveNodeUp(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound) { // get the current layer in the map of stacked layers RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIterator = stackedLayers.find(currentLayer); if (layerStackIterator != stackedLayers.end() && layerStackIterator != stackedLayers.begin()) { // found the element in the map, at different position than 'begin' -> // current node is not on the topmost layer and therefore can be moved one layer up // swap the layers of the dataNode and the dataNode on the next higher layer (previous map element) RenderWindowLayerUtilities::LayerStack::const_iterator prevLayerStackIterator = std::prev(layerStackIterator); dataNode->SetIntProperty("layer", prevLayerStackIterator->first, renderer); prevLayerStackIterator->second->SetIntProperty("layer", currentLayer, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: layer stack does not contain a layer with the 'currentLayer'data node or // layer is already the topmost layer node } // else: data node has no layer information } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeDown(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node up in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { MoveNodeDown(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound) { // get the current layer in the map of stacked layers RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIterator = stackedLayers.find(currentLayer); if (layerStackIterator != stackedLayers.end()) { // found the element in the map ... RenderWindowLayerUtilities::LayerStack::const_iterator nextLayerStackIterator = std::next(layerStackIterator); if (nextLayerStackIterator != stackedLayers.end()) { // ... and found a successor -> // current node is not on the lowermost layer and therefore can be moved one layer down // swap the layers of the dataNode and the dataNode on the next lower layer (next map element) dataNode->SetIntProperty("layer", nextLayerStackIterator->first, renderer); nextLayerStackIterator->second->SetIntProperty("layer", currentLayer, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node is already the lowermost layer node } // else: layer stack does not contain a layer with the 'currentLayer' } // else: data node has no layer information } // else: do not work with empty layer stack } return false; } void mitk::RenderWindowLayerController::SetVisibilityOfDataNode(bool visibility, DataNode* dataNode, const BaseRenderer* renderer /*=nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // set visibility of data node in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { SetVisibilityOfDataNode(visibility, dataNode, renderer); } } } else { dataNode->SetVisibility(visibility, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } void mitk::RenderWindowLayerController::HideDataNodeInAllRenderer(const DataNode* dataNode) { if (nullptr == dataNode) { return; } for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { dataNode->GetPropertyList(renderer)->SetBoolProperty("visible", false); } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::RenderWindowLayerController::ResetRenderer(bool onlyVisibility /*= true*/, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == renderer) { // reset all controlled renderer for (const auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { ResetRenderer(onlyVisibility, renderer); } } } else { // get the layer stack with the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, true); if (!stackedLayers.empty()) { for (const auto& layer : stackedLayers) { int layerLevel; layer.second->GetIntProperty("layer", layerLevel, renderer); if (RenderWindowLayerUtilities::BASE_LAYER_INDEX == layerLevel) { // set base data node visibility to true layer.second->SetVisibility(true, renderer); } else { // set visibility of all other data nodes to false layer.second->SetVisibility(false, renderer); // modify layer node if (!onlyVisibility) { // clear mode: additionally remove layer node from current renderer layer.second->GetPropertyList(renderer)->DeleteProperty("layer"); layer.second->SetBoolProperty("fixedLayer", false, renderer); } } layer.second->Modified(); } mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } } diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp index 29ac67fbd1..b3fd2e8a12 100644 --- a/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp +++ b/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp @@ -1,63 +1,68 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager module #include "mitkRenderWindowLayerUtilities.h" // mitk core -#include #include -#include +#include -RenderWindowLayerUtilities::LayerStack RenderWindowLayerUtilities::GetLayerStack(const mitk::DataStorage* dataStorage, const mitk::BaseRenderer* renderer, bool withBaseNode) +mitk::RenderWindowLayerUtilities::LayerStack mitk::RenderWindowLayerUtilities::GetLayerStack(const DataStorage* dataStorage, const BaseRenderer* renderer, bool withBaseNode) { LayerStack stackedLayers; if (nullptr == dataStorage || nullptr == renderer) { // no nodes to stack or no renderer selected return stackedLayers; } int layer = -1; - mitk::NodePredicateProperty::Pointer helperObject = mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)); - mitk::NodePredicateNot::Pointer notAHelperObject = mitk::NodePredicateNot::New(helperObject); - - mitk::NodePredicateProperty::Pointer fixedLayer = mitk::NodePredicateProperty::New("fixedLayer", mitk::BoolProperty::New(true), renderer); - - // combine node predicates - mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::NodePredicateAnd::New(notAHelperObject, fixedLayer); - mitk::DataStorage::SetOfObjects::ConstPointer filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate); - - for (mitk::DataStorage::SetOfObjects::ConstIterator it = filteredDataNodes->Begin(); it != filteredDataNodes->End(); ++it) + NodePredicateAnd::Pointer combinedNodePredicate = GetRenderWindowPredicate(renderer); + DataStorage::SetOfObjects::ConstPointer filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate); + for (DataStorage::SetOfObjects::ConstIterator it = filteredDataNodes->Begin(); it != filteredDataNodes->End(); ++it) { - mitk::DataNode::Pointer dataNode = it->Value(); + DataNode::Pointer dataNode = it->Value(); if (dataNode.IsNull()) { continue; } bool layerFound = dataNode->GetIntProperty("layer", layer, renderer); if (layerFound) { if (BASE_LAYER_INDEX != layer|| withBaseNode) { // data node is not on the base layer or the base layer should be included anyway stackedLayers.insert(std::make_pair(layer, dataNode)); } } } return stackedLayers; } + +mitk::NodePredicateAnd::Pointer mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(const BaseRenderer* renderer) +{ + NodePredicateAnd::Pointer renderWindowPredicate = NodePredicateAnd::New(); + + NodePredicateProperty::Pointer helperObject = NodePredicateProperty::New("helper object", BoolProperty::New(true)); + NodePredicateProperty::Pointer fixedLayer = NodePredicateProperty::New("fixedLayer", BoolProperty::New(true), renderer); + + renderWindowPredicate->AddPredicate(NodePredicateNot::New(helperObject)); + renderWindowPredicate->AddPredicate(fixedLayer); + + return renderWindowPredicate; +} diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowViewDirectionController.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowViewDirectionController.cpp index c149b2d814..8eed3a7b6c 100644 --- a/Modules/RenderWindowManager/src/mitkRenderWindowViewDirectionController.cpp +++ b/Modules/RenderWindowManager/src/mitkRenderWindowViewDirectionController.cpp @@ -1,110 +1,141 @@ /*=================================================================== 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 "mitkRenderWindowViewDirectionController.h" -// mitk +// mitk core #include #include #include mitk::RenderWindowViewDirectionController::RenderWindowViewDirectionController() : m_DataStorage(nullptr) { // nothing here } void mitk::RenderWindowViewDirectionController::SetDataStorage(DataStorage::Pointer dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage m_DataStorage = dataStorage; } } void mitk::RenderWindowViewDirectionController::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { if (m_ControlledRenderer != controlledRenderer) { // set the new set of controlled renderer m_ControlledRenderer = controlledRenderer; } } -void mitk::RenderWindowViewDirectionController::SetViewDirectionOfRenderer(const std::string &viewDirection, BaseRenderer* renderer /*=nullptr*/) +void mitk::RenderWindowViewDirectionController::SetViewDirectionOfRenderer(const std::string& viewDirection, BaseRenderer* renderer/* =nullptr*/) { if (nullptr == renderer) { - // set visibility of data node in all controlled renderer for (auto& renderer : m_ControlledRenderer) { - if (renderer.IsNotNull()) + if (nullptr != renderer) { - //SetViewDirectionOfRenderer(viewDirection, renderer); + SetViewDirectionOfRenderer(viewDirection, renderer); } } } else { mitk::SliceNavigationController* sliceNavigationController = renderer->GetSliceNavigationController(); if ("axial" == viewDirection) { - sliceNavigationController->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + sliceNavigationController->SetDefaultViewDirection(ViewDirection::Axial); } else if ("coronal" == viewDirection) { - sliceNavigationController->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); + sliceNavigationController->SetDefaultViewDirection(ViewDirection::Frontal); } else if ("sagittal" == viewDirection) { - sliceNavigationController->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + sliceNavigationController->SetDefaultViewDirection(ViewDirection::Sagittal); + } + + if ("3D" == viewDirection) + { + renderer->SetMapperID(mitk::BaseRenderer::Standard3D); + } + else + { + renderer->SetMapperID(mitk::BaseRenderer::Standard2D); + + } + // initialize the views to the bounding geometry + InitializeViewByBoundingObjects(renderer); + } +} + +void mitk::RenderWindowViewDirectionController::SetViewDirectionOfRenderer(ViewDirection viewDirection , BaseRenderer* renderer/* =nullptr*/) +{ + if (nullptr == renderer) + { + // set visibility of data node in all controlled renderer + for (auto& renderer : m_ControlledRenderer) + { + if (nullptr != renderer) + { + SetViewDirectionOfRenderer(viewDirection, renderer); + } } + } + else + { + mitk::SliceNavigationController* sliceNavigationController = renderer->GetSliceNavigationController(); + sliceNavigationController->SetDefaultViewDirection(viewDirection); // initialize the views to the bounding geometry InitializeViewByBoundingObjects(renderer); } } void mitk::RenderWindowViewDirectionController::InitializeViewByBoundingObjects(const BaseRenderer* renderer) { if (nullptr == m_DataStorage || nullptr == renderer) { return; } // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateProperty::Pointer includeInBoundingBox = mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false)); mitk::NodePredicateNot::Pointer notIncludeInBoundingBox = mitk::NodePredicateNot::New(includeInBoundingBox); // get all non-helper objects mitk::NodePredicateProperty::Pointer helperObject = mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer notAHelperObject = mitk::NodePredicateNot::New(helperObject); // get all nodes that have a fixed layer for the given renderer mitk::NodePredicateProperty::Pointer fixedLayer = mitk::NodePredicateProperty::New("fixedLayer", mitk::BoolProperty::New(true), renderer); // combine node predicates mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::NodePredicateAnd::New(notIncludeInBoundingBox, notAHelperObject, fixedLayer); mitk::DataStorage::SetOfObjects::ConstPointer filteredDataNodes = m_DataStorage->GetSubset(combinedNodePredicate); // calculate bounding geometry of these nodes auto bounds = m_DataStorage->ComputeBoundingGeometry3D(filteredDataNodes, "visible", renderer); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeView(renderer->GetRenderWindow(), bounds); -} \ No newline at end of file +} diff --git a/Modules/RenderWindowManagerUI/CMakeLists.txt b/Modules/RenderWindowManagerUI/CMakeLists.txt index f94ad95c26..7f5d63fa95 100644 --- a/Modules/RenderWindowManagerUI/CMakeLists.txt +++ b/Modules/RenderWindowManagerUI/CMakeLists.txt @@ -1,5 +1,4 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS Qmitk DEPENDS MitkQtWidgets MitkRenderWindowManager - PACKAGE_DEPENDS PUBLIC CTK Qt5|Core + PACKAGE_DEPENDS PUBLIC Qt5|Core ) diff --git a/Modules/RenderWindowManagerUI/files.cmake b/Modules/RenderWindowManagerUI/files.cmake index a350cab98c..1637b1a861 100644 --- a/Modules/RenderWindowManagerUI/files.cmake +++ b/Modules/RenderWindowManagerUI/files.cmake @@ -1,18 +1,18 @@ set(H_FILES - include/QmitkRenderWindowManipulatorWidget.h - include/QmitkDataStorageLayerStackModel.h + include/QmitkRenderWindowDataStorageInspector.h + include/QmitkRenderWindowDataStorageListModel.h ) set(CPP_FILES - QmitkRenderWindowManipulatorWidget.cpp - QmitkDataStorageLayerStackModel.cpp + QmitkRenderWindowDataStorageInspector.cpp + QmitkRenderWindowDataStorageListModel.cpp ) set(MOC_H_FILES - include/QmitkRenderWindowManipulatorWidget.h - include/QmitkDataStorageLayerStackModel.h + include/QmitkRenderWindowDataStorageInspector.h + include/QmitkRenderWindowDataStorageListModel.h ) set(UI_FILES - src/QmitkRenderWindowManipulatorWidget.ui -) \ No newline at end of file + src/QmitkRenderWindowDataStorageInspector.ui +) diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h new file mode 100644 index 0000000000..d0078bb2dc --- /dev/null +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h @@ -0,0 +1,94 @@ +/*=================================================================== + +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 QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H +#define QMITKRENDERWINDOWDATASTORAGEWINSPECTOR_H + +// render window manager UI module +#include "MitkRenderWindowManagerUIExports.h" +#include "ui_QmitkRenderWindowDataStorageInspector.h" + +// render window manager module +#include +#include +#include + +// qt widgets module +#include + +/** +* The 'QmitkRenderWindowDataStorageInspector' offers a GUI to manipulate the base renderer / render windows of the MITK workbench. +* +* In order to use this widget, a (e.g.) plugin has to set the controlled renderer, which will be forwarded to +* a render window view direction controller. +*/ +class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + + QmitkRenderWindowDataStorageInspector(QWidget* parent = nullptr); + + // override from 'QmitkAbstractDataStorageInspector' + /** + * @brief See 'QmitkAbstractDataStorageInspector' + */ + virtual QAbstractItemView* GetView() override; + /** + * @brief See 'QmitkAbstractDataStorageInspector' + */ + virtual const QAbstractItemView* GetView() const override; + /** + * @brief See 'QmitkAbstractDataStorageInspector' + */ + virtual void SetSelectionMode(SelectionMode mode) override; + /** + * @brief See 'QmitkAbstractDataStorageInspector' + */ + virtual SelectionMode GetSelectionMode() const override; + /** + * @brief Set the controlled base renderer. + */ + void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer); + /** + * @brief Set the currently selected render window. + * + * @param renderWindowId the text inside the combo box + */ + void SetActiveRenderWindow(const QString& renderWindowId); + +private Q_SLOTS: + + void SetAsBaseLayer(); + + void ResetRenderer(); + + void ChangeViewDirection(const QString& viewDirection); + +private: + + virtual void Initialize() override; + void SetUpConnections(); + + Ui::QmitkRenderWindowDataStorageInspector m_Controls; + + std::unique_ptr m_StorageModel; + std::unique_ptr m_RenderWindowLayerController; + std::unique_ptr m_RenderWindowViewDirectionController; +}; + +#endif // QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h new file mode 100644 index 0000000000..1040964249 --- /dev/null +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h @@ -0,0 +1,108 @@ +/*=================================================================== + +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 QMITKDATASTORAGERENDERWINDOWLISTMODEL_H +#define QMITKDATASTORAGERENDERWINDOWLISTMODEL_H + +// render window manager UI model +#include "MitkRenderWindowManagerUIExports.h" + +// render window manager module +#include "mitkRenderWindowLayerController.h" +#include "mitkRenderWindowLayerUtilities.h" + +//mitk core +#include + +// qt widgets module +#include + +/* +* @brief The 'QmitkDataStorageRenderWindowListModel' is a list model derived from the 'QmitkAbstractDataStorageModel'. +*/ +class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageListModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkRenderWindowDataStorageListModel(QObject* parent = nullptr); + + // override from 'QmitkAbstractDataStorageModel' + /** + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /** + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /** + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /** + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /** + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; + + // override from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + + QVariant data(const QModelIndex& index, int role) const override; + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + + Qt::ItemFlags flags(const QModelIndex& index) const override; + + Qt::DropActions supportedDropActions() const override; + Qt::DropActions supportedDragActions() const override; + QStringList mimeTypes() const override; + QMimeData* mimeData(const QModelIndexList& indexes) const override; + + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; + + void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer); + + void SetCurrentRenderer(mitk::BaseRenderer* baseRenderer); + mitk::BaseRenderer* GetCurrentRenderer() const; + + /** + * @brief Use the RenderWindowLayerController to insert the given data node into all controlled render windows. + * The new node is placed on top of all existing layer nodes in the render window. + * + * @param dataNode The data node that should be inserted. + */ + void AddDataNodeToAllRenderer(mitk::DataNode* dataNode); + +private: + + void UpdateModelData(); + + std::unique_ptr m_RenderWindowLayerController; + mitk::WeakPointer m_BaseRenderer; + mitk::RenderWindowLayerUtilities::LayerStack m_LayerStack; + +}; + +#endif // QMITKDATASTORAGERENDERWINDOWLISTMODEL_H diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h deleted file mode 100644 index c863b88052..0000000000 --- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h +++ /dev/null @@ -1,114 +0,0 @@ -/*=================================================================== - -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 QMITKRENDERWINDOWMANIPULATORWIDGET_H -#define QMITKRENDERWINDOWMANIPULATORWIDGET_H - -// render window manager UI module -#include "MitkRenderWindowManagerUIExports.h" -#include "ui_QmitkRenderWindowManipulatorWidget.h" -#include - -// render window manager module -#include -#include - -// qt -#include - -/** -* The QmitkRenderWindowManipulatorWidget offers a GUI to manipulate the base renderer / render windows of the MITK workbench. -* The widgets supports adding a layer to an active render window, moving layers up and down, removing layers, -* resetting layers (hiding them) or removing all layers at once. -* -* In order to use this widget, a (e.g.) plugin has to set the controlled renderer, which will be forwarded to -* a render window layer controller and a render window view direction controller. -* The plugin also has to provide a Q_SLOT that is connected to the 'AddLayerButtonClicked'-Q_SIGNAL of this widget. -* This allows for a customized add-layer functionality. -*/ -class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowManipulatorWidget : public QWidget -{ - Q_OBJECT - -public: - - QmitkRenderWindowManipulatorWidget(mitk::DataStorage::Pointer dataStorage, QWidget* parent = nullptr); - /** - * @brief Get the table view that displays the layer stack inside this widget - */ - QTableView* GetLayerStackTableView(); - /** - * @brief Set the controlled base renderer. - */ - void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); - /** - * @brief Set the currently selected render window - * - * @param renderWindowId the text inside the combo box - */ - void SetActiveRenderWindow(const QString &renderWindowId); - /** - * @brief Use the RenderWindowLayerController to insert the given data node into the currently active render window. - * The new node is placed on top of all existing layer nodes in that render window. - * - * @param dataNode The data node that should be inserted. - */ - void AddLayer(mitk::DataNode* dataNode); - /** - * @brief Use the RenderWindowLayerController to insert the given data node into all controlled render windows. - * The new node is placed on top of all existing layer nodes in the render window. - * - * @param dataNode The data node that should be inserted. - */ - void AddLayerToAllRenderer(mitk::DataNode* dataNode); - /** - * @brief Use the RenderWindowLayerController to hide the given data node in the currently active render window. - * - * @param dataNode The data node that should be hid. - */ - void HideDataNodeInAllRenderer(const mitk::DataNode* dataNode); - -Q_SIGNALS: - - void AddLayerButtonClicked(); - -private Q_SLOTS: - - void RemoveLayer(); - void SetAsBaseLayer(); - - void MoveLayer(const QString &direction); - - void ResetRenderer(); - void ClearRenderer(); - - void ChangeViewDirection(const QString &viewDirection); - -private: - - void Init(); - void SetUpConnections(); - - Ui::QmitkRenderWindowManipulatorWidget m_Controls; - - mitk::DataStorage::Pointer m_DataStorage; - std::unique_ptr m_RenderWindowLayerController; - std::unique_ptr m_RenderWindowViewDirectionController; - - QmitkDataStorageLayerStackModel* m_StorageModel; -}; - -#endif // QMITKRENDERWINDOWMANIPULATORWIDGET_H diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp new file mode 100644 index 0000000000..018d3441f0 --- /dev/null +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp @@ -0,0 +1,165 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// render window manager UI module +#include "QmitkRenderWindowDataStorageInspector.h" + +#include "QmitkCustomVariants.h" + +// mitk core +#include + +// qt +#include + +QmitkRenderWindowDataStorageInspector::QmitkRenderWindowDataStorageInspector(QWidget* parent /*=nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + // initialize the render window layer controller and the render window view direction controller + m_RenderWindowLayerController = std::make_unique(); + m_RenderWindowViewDirectionController = std::make_unique(); + + m_StorageModel = std::make_unique(this); + + m_Controls.renderWindowListView->setModel(m_StorageModel.get()); + m_Controls.renderWindowListView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_Controls.renderWindowListView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.renderWindowListView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.renderWindowListView->setAlternatingRowColors(true); + m_Controls.renderWindowListView->setDragEnabled(true); + m_Controls.renderWindowListView->setDropIndicatorShown(true); + m_Controls.renderWindowListView->setAcceptDrops(true); + m_Controls.renderWindowListView->setContextMenuPolicy(Qt::CustomContextMenu); + + SetUpConnections(); +} + +QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() +{ + return m_Controls.renderWindowListView; +} + +const QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() const +{ + return m_Controls.renderWindowListView; +} + +void QmitkRenderWindowDataStorageInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.renderWindowListView->setSelectionMode(mode); +} + +QmitkRenderWindowDataStorageInspector::SelectionMode QmitkRenderWindowDataStorageInspector::GetSelectionMode() const +{ + return m_Controls.renderWindowListView->selectionMode(); +} + +void QmitkRenderWindowDataStorageInspector::Initialize() +{ + if (m_DataStorage.IsExpired()) + { + return; + } + + auto dataStorage = m_DataStorage.Lock(); + + m_StorageModel->SetDataStorage(dataStorage); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_RenderWindowLayerController->SetDataStorage(dataStorage); + m_RenderWindowViewDirectionController->SetDataStorage(dataStorage); + + m_Connector->SetView(m_Controls.renderWindowListView); +} + +void QmitkRenderWindowDataStorageInspector::SetUpConnections() +{ + connect(m_Controls.pushButtonSetAsBaseLayer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::SetAsBaseLayer); + connect(m_Controls.pushButtonResetRenderer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::ResetRenderer); + + QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this); + changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial")); + changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal")); + changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal")); + changeViewDirectionSignalMapper->setMapping(m_Controls.radioButton3D, QString("3D")); + connect(changeViewDirectionSignalMapper, static_cast(&QSignalMapper::mapped), this, &QmitkRenderWindowDataStorageInspector::ChangeViewDirection); + + connect(m_Controls.radioButtonAxial, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); + connect(m_Controls.radioButtonCoronal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); + connect(m_Controls.radioButtonSagittal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); + connect(m_Controls.radioButton3D, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); +} + +void QmitkRenderWindowDataStorageInspector::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) +{ + m_StorageModel->SetControlledRenderer(controlledRenderer); + m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); + m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); +} + +void QmitkRenderWindowDataStorageInspector::SetActiveRenderWindow(const QString& renderWindowId) +{ + mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(renderWindowId.toStdString()); + if (nullptr == selectedRenderer) + { + return; + } + + m_StorageModel->SetCurrentRenderer(selectedRenderer); + mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); + switch (viewDirection) + { + case mitk::SliceNavigationController::Axial: + m_Controls.radioButtonAxial->setChecked(true); + break; + case mitk::SliceNavigationController::Frontal: + m_Controls.radioButtonCoronal->setChecked(true); + break; + case mitk::SliceNavigationController::Sagittal: + m_Controls.radioButtonSagittal->setChecked(true); + break; + default: + break; + } +} + +void QmitkRenderWindowDataStorageInspector::SetAsBaseLayer() +{ + QModelIndex selectedIndex = m_Controls.renderWindowListView->currentIndex(); + if (selectedIndex.isValid()) + { + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, Qt::UserRole); + if (qvariantDataNode.canConvert()) + { + mitk::DataNode* dataNode = qvariantDataNode.value(); + m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer()); + m_Controls.renderWindowListView->clearSelection(); + } + } +} + +void QmitkRenderWindowDataStorageInspector::ResetRenderer() +{ + m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); + m_Controls.renderWindowListView->clearSelection(); +} + +void QmitkRenderWindowDataStorageInspector::ChangeViewDirection(const QString& viewDirection) +{ + m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer()); +} diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui similarity index 61% rename from Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui rename to Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui index b0db32738a..64c507a340 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui @@ -1,120 +1,92 @@ - QmitkRenderWindowManipulatorWidget - + QmitkRenderWindowDataStorageInspector + 0 0 - 308 + 340 246 0 0 0 0 Render window manager Render window overview - + - - - - Add Layer - - - - - - - Remove layer - - - - - - - Set as base layer - - - - - - - Move up - - - - - - - Move down - - - - + Reset render window - - + + - Clear render window + Set as base layer - + Axial true - + Coronal - + Sagittal + + + + 3D + + + diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp new file mode 100644 index 0000000000..7c456fa3c6 --- /dev/null +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp @@ -0,0 +1,358 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// render window manager UI module +#include "QmitkRenderWindowDataStorageListModel.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" +#include "QmitkMimeTypes.h" +#include "QmitkNodeDescriptorManager.h" + +QmitkRenderWindowDataStorageListModel::QmitkRenderWindowDataStorageListModel(QObject* parent /*= nullptr*/) + : QmitkAbstractDataStorageModel(parent) +{ + m_RenderWindowLayerController = std::make_unique(); +} + +void QmitkRenderWindowDataStorageListModel::DataStorageChanged() +{ + m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock()); + UpdateModelData(); +} + +void QmitkRenderWindowDataStorageListModel::NodePredicateChanged() +{ + UpdateModelData(); +} + +void QmitkRenderWindowDataStorageListModel::NodeAdded(const mitk::DataNode* node) +{ + // add a node to each render window specific list (or to a global list initially) + AddDataNodeToAllRenderer(const_cast(node)); + UpdateModelData(); +} + +void QmitkRenderWindowDataStorageListModel::NodeChanged(const mitk::DataNode* /*node*/) +{ + // nothing here, since the "'NodeChanged'-event is currently sent far too often +} + +void QmitkRenderWindowDataStorageListModel::NodeRemoved(const mitk::DataNode* /*node*/) +{ + // update model data to create a new list without the removed data node + UpdateModelData(); +} + +QModelIndex QmitkRenderWindowDataStorageListModel::index(int row, int column, const QModelIndex& parent) const +{ + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) + { + return this->createIndex(row, column); + } + + return QModelIndex(); +} + +QModelIndex QmitkRenderWindowDataStorageListModel::parent(const QModelIndex& /*child*/) const +{ + return QModelIndex(); +} + +int QmitkRenderWindowDataStorageListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const +{ + if (parent.isValid()) + { + return 0; + } + + return static_cast(m_LayerStack.size()); +} + +int QmitkRenderWindowDataStorageListModel::columnCount(const QModelIndex& parent /*= QModelIndex()*/) const +{ + if (parent.isValid()) + { + return 0; + } + + return 1; +} + +QVariant QmitkRenderWindowDataStorageListModel::data(const QModelIndex& index, int role) const +{ + if (m_BaseRenderer.IsExpired()) + { + return QVariant(); + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + if (!index.isValid() || this != index.model()) + { + return QVariant(); + } + + if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size())) + { + return QVariant(); + } + + mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin(); + std::advance(layerStackIt, index.row()); + mitk::DataNode* dataNode = layerStackIt->second; + + if (Qt::CheckStateRole == role) + { + bool visibility = false; + dataNode->GetVisibility(visibility, baseRenderer); + if (visibility) + { + return Qt::Checked; + } + else + { + return Qt::Unchecked; + } + } + else if (Qt::DisplayRole == role) + { + return QVariant(QString::fromStdString(dataNode->GetName())); + } + else if (Qt::ToolTipRole == role) + { + return QVariant("Name of the data node."); + } + else if (Qt::DecorationRole == role) + { + QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role) + { + // user role always returns a reference to the data node, + // which can be used to modify the data node in the data storage + return QVariant::fromValue(dataNode); + } + else if (QmitkDataNodeRole == role) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + + return QVariant(); +} + +bool QmitkRenderWindowDataStorageListModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) +{ + if (m_BaseRenderer.IsExpired()) + { + return false; + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + if (!index.isValid() || this != index.model()) + { + return false; + } + + if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size())) + { + return false; + } + + mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin(); + std::advance(layerStackIt, index.row()); + mitk::DataNode* dataNode = layerStackIt->second; + if (Qt::CheckStateRole == role) + { + Qt::CheckState newCheckState = static_cast(value.toInt()); + bool isVisible = newCheckState; + dataNode->SetVisibility(isVisible, baseRenderer); + + emit dataChanged(index, index); + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + return true; + } + return false; +} + +Qt::ItemFlags QmitkRenderWindowDataStorageListModel::flags(const QModelIndex &index) const +{ + if (this != index.model()) + { + return Qt::NoItemFlags; + } + + if (!index.isValid()) + { + return Qt::ItemIsDropEnabled; + } + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; +} + +Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDropActions() const +{ + return Qt::CopyAction | Qt::MoveAction; +} + +Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDragActions() const +{ + return Qt::CopyAction | Qt::MoveAction; +} + +QStringList QmitkRenderWindowDataStorageListModel::mimeTypes() const +{ + QStringList types = QAbstractItemModel::mimeTypes(); + types << QmitkMimeTypes::DataNodePtrs; + return types; +} + +QMimeData* QmitkRenderWindowDataStorageListModel::mimeData(const QModelIndexList& indexes) const +{ + QMimeData* mimeData = new QMimeData(); + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + for (const auto& index : indexes) + { + if (index.isValid()) + { + auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); + stream << reinterpret_cast(dataNode); + } + } + + mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); + return mimeData; +} + +bool QmitkRenderWindowDataStorageListModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int column, const QModelIndex& parent) +{ + if (m_BaseRenderer.IsExpired()) + { + return false; + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + if (action == Qt::IgnoreAction) + { + return true; + } + + if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) + { + return false; + } + + if (column > 0) + { + return false; + } + + if (parent.isValid()) + { + int layer = -1; + auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); + if (nullptr != dataNode) + { + dataNode->GetIntProperty("layer", layer, baseRenderer); + } + + auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); + for (const auto& dataNode : dataNodeList) + { + m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); + } + + UpdateModelData(); + return true; + } + + return false; +} + +void QmitkRenderWindowDataStorageListModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) +{ + m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + mitk::DataStorage::SetOfObjects::ConstPointer allDataNodes = dataStorage->GetAll(); + for (mitk::DataStorage::SetOfObjects::ConstIterator it = allDataNodes->Begin(); it != allDataNodes->End(); ++it) + { + mitk::DataNode::Pointer dataNode = it->Value(); + if (dataNode.IsNull()) + { + continue; + } + + AddDataNodeToAllRenderer(dataNode); + } + } +} + +void QmitkRenderWindowDataStorageListModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) +{ + if (m_BaseRenderer == baseRenderer) + { + return; + } + + m_BaseRenderer = baseRenderer; + if (!m_BaseRenderer.IsExpired()) + { + UpdateModelData(); + } +} + +mitk::BaseRenderer* QmitkRenderWindowDataStorageListModel::GetCurrentRenderer() const +{ + if (m_BaseRenderer.IsExpired()) + { + return nullptr; + } + + return m_BaseRenderer.Lock().GetPointer(); +} + +void QmitkRenderWindowDataStorageListModel::AddDataNodeToAllRenderer(mitk::DataNode* dataNode) +{ + m_RenderWindowLayerController->InsertLayerNode(dataNode); +} + +void QmitkRenderWindowDataStorageListModel::UpdateModelData() +{ + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + if (!m_BaseRenderer.IsExpired()) + { + auto baseRenderer = m_BaseRenderer.Lock(); + // update the model, so that it will be filled with the nodes of the new data storage + beginResetModel(); + // get the current layer stack of the given base renderer + m_LayerStack = mitk::RenderWindowLayerUtilities::GetLayerStack(dataStorage, baseRenderer, true); + endResetModel(); + } + } +} diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp deleted file mode 100644 index cb8ad4eb8e..0000000000 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -// render window manager UI module -#include "QmitkRenderWindowManipulatorWidget.h" - -// qt widgets module -#include "QmitkCustomVariants.h" -#include "QmitkEnums.h" - -// mitk core -#include - -// qt -#include - -QmitkRenderWindowManipulatorWidget::QmitkRenderWindowManipulatorWidget(mitk::DataStorage::Pointer dataStorage, QWidget* parent /*=nullptr*/) - : QWidget(parent) - , m_DataStorage(dataStorage) - , m_StorageModel(nullptr) -{ - Init(); -} - -void QmitkRenderWindowManipulatorWidget::Init() -{ - m_Controls.setupUi(this); - - // initialize the render window layer controller and the render window view direction controller - // and set the controller renderer (in constructor) and the data storage - m_RenderWindowLayerController = std::make_unique(); - m_RenderWindowViewDirectionController = std::make_unique(); - m_RenderWindowLayerController->SetDataStorage(m_DataStorage); - m_RenderWindowViewDirectionController->SetDataStorage(m_DataStorage); - - m_Controls.layerStackTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_Controls.layerStackTableView->horizontalHeader()->setStretchLastSection(true); - m_Controls.layerStackTableView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_Controls.layerStackTableView->setSelectionMode(QAbstractItemView::SingleSelection); - - m_StorageModel = new QmitkDataStorageLayerStackModel(this); - m_StorageModel->SetDataStorage(m_DataStorage); - - m_Controls.layerStackTableView->setModel(m_StorageModel); - - SetUpConnections(); -} - -void QmitkRenderWindowManipulatorWidget::SetUpConnections() -{ - // signal to signal connection - connect(m_Controls.pushButtonAddLayer, SIGNAL(clicked()), this, SIGNAL(AddLayerButtonClicked())); - connect(m_Controls.pushButtonRemoveLayer, SIGNAL(clicked()), this, SLOT(RemoveLayer())); - connect(m_Controls.pushButtonSetAsBaseLayer, SIGNAL(clicked()), this, SLOT(SetAsBaseLayer())); - - QSignalMapper* udSignalMapper = new QSignalMapper(this); - udSignalMapper->setMapping(m_Controls.pushButtonMoveUp, QString("up")); - udSignalMapper->setMapping(m_Controls.pushButtonMoveDown, QString("down")); - connect(udSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(MoveLayer(const QString&))); - connect(m_Controls.pushButtonMoveUp, SIGNAL(clicked()), udSignalMapper, SLOT(map())); - connect(m_Controls.pushButtonMoveDown, SIGNAL(clicked()), udSignalMapper, SLOT(map())); - - connect(m_Controls.pushButtonResetRenderer, SIGNAL(clicked()), this, SLOT(ResetRenderer())); - connect(m_Controls.pushButtonClearRenderer, SIGNAL(clicked()), this, SLOT(ClearRenderer())); - - QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this); - changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial")); - changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal")); - changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal")); - connect(changeViewDirectionSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(ChangeViewDirection(const QString&))); - connect(m_Controls.radioButtonAxial, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); - connect(m_Controls.radioButtonCoronal, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); - connect(m_Controls.radioButtonSagittal, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); -} - -QTableView* QmitkRenderWindowManipulatorWidget::GetLayerStackTableView() -{ - return m_Controls.layerStackTableView; -} - -void QmitkRenderWindowManipulatorWidget::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) -{ - m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); - m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); -} - -void QmitkRenderWindowManipulatorWidget::SetActiveRenderWindow(const QString &renderWindowId) -{ - if (nullptr == m_StorageModel) - { - return; - } - - std::string currentRendererName = renderWindowId.toStdString(); - m_StorageModel->SetCurrentRenderer(currentRendererName); - - mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(currentRendererName); - if (nullptr == selectedRenderer) - { - return; - } - - mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); - switch (viewDirection) - { - case mitk::SliceNavigationController::Axial: - m_Controls.radioButtonAxial->setChecked(true); - break; - case mitk::SliceNavigationController::Frontal: - m_Controls.radioButtonCoronal->setChecked(true); - break; - case mitk::SliceNavigationController::Sagittal: - m_Controls.radioButtonSagittal->setChecked(true); - break; - default: - break; - } -} - -void QmitkRenderWindowManipulatorWidget::AddLayer(mitk::DataNode* dataNode) -{ - if (nullptr == m_StorageModel) - { - return; - } - - m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, m_StorageModel->GetCurrentRenderer()); -} - -void QmitkRenderWindowManipulatorWidget::AddLayerToAllRenderer(mitk::DataNode* dataNode) -{ - m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, nullptr); -} - -void QmitkRenderWindowManipulatorWidget::HideDataNodeInAllRenderer(const mitk::DataNode* dataNode) -{ - m_RenderWindowLayerController->HideDataNodeInAllRenderer(dataNode); -} - -void QmitkRenderWindowManipulatorWidget::RemoveLayer() -{ - if (nullptr == m_StorageModel) - { - return; - } - - QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); - if (selectedIndex.isValid()) - { - - QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); - if (qvariantDataNode.canConvert()) - { - mitk::DataNode* dataNode = qvariantDataNode.value(); - m_RenderWindowLayerController->RemoveLayerNode(dataNode, m_StorageModel->GetCurrentRenderer()); - m_Controls.layerStackTableView->clearSelection(); - } - } -} - -void QmitkRenderWindowManipulatorWidget::SetAsBaseLayer() -{ - if (nullptr == m_StorageModel) - { - return; - } - - QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); - if (selectedIndex.isValid()) - { - QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); - if (qvariantDataNode.canConvert()) - { - mitk::DataNode* dataNode = qvariantDataNode.value(); - m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer()); - m_Controls.layerStackTableView->clearSelection(); - } - } -} - -void QmitkRenderWindowManipulatorWidget::MoveLayer(const QString &direction) -{ - if (nullptr == m_StorageModel) - { - return; - } - - QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); - if (selectedIndex.isValid()) - { - QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); - if (qvariantDataNode.canConvert()) - { - mitk::DataNode* dataNode = qvariantDataNode.value(); - const mitk::BaseRenderer* selectedRenderer = m_StorageModel->GetCurrentRenderer(); - - bool success = false; - if ("up" == direction) - { - success = m_RenderWindowLayerController->MoveNodeUp(dataNode, selectedRenderer); - if (success) - { - // node has been successfully moved up - QTableView* tableView = dynamic_cast(m_Controls.layerStackTableView); - if (nullptr != tableView) - { - tableView->selectRow(selectedIndex.row() - 1); - } - } - } - else - { - success = m_RenderWindowLayerController->MoveNodeDown(dataNode, selectedRenderer); - if (success) - { - // node has been successfully moved down - QTableView* tableView = dynamic_cast(m_Controls.layerStackTableView); - if (nullptr != tableView) - { - tableView->selectRow(selectedIndex.row() + 1); - } - } - } - } - } -} - -void QmitkRenderWindowManipulatorWidget::ResetRenderer() -{ - if (nullptr == m_StorageModel) - { - return; - } - - m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); - m_Controls.layerStackTableView->clearSelection(); -} - -void QmitkRenderWindowManipulatorWidget::ClearRenderer() -{ - if (nullptr == m_StorageModel) - { - return; - } - - m_RenderWindowLayerController->ResetRenderer(false, m_StorageModel->GetCurrentRenderer()); - m_Controls.layerStackTableView->clearSelection(); -} - -void QmitkRenderWindowManipulatorWidget::ChangeViewDirection(const QString &viewDirection) -{ - if (nullptr == m_StorageModel) - { - return; - - } - - m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer()); -} diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index f3316ce4d6..4446b8ab1a 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,115 +1,116 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON + org.mitk.gui.qt.mxnmultiwidgeteditor:OFF org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.chartExample:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.diffusionimaging.python:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.semanticrelations:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.pausmotioncompensation:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.photoacoustics.spectralunmixing:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.radiomics:OFF org.mitk.gui.qt.cest:OFF org.mitk.gui.qt.fit.demo:OFF org.mitk.gui.qt.fit.inspector:OFF org.mitk.gui.qt.fit.genericfitting:OFF org.mitk.gui.qt.pharmacokinetics.mri:OFF org.mitk.gui.qt.pharmacokinetics.pet:OFF org.mitk.gui.qt.pharmacokinetics.simulation:OFF org.mitk.gui.qt.pharmacokinetics.curvedescriptor:OFF org.mitk.gui.qt.pharmacokinetics.concentration.mri:OFF ) diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.cpp index c1ffcf01b5..2cd7aab4a0 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.cpp @@ -1,888 +1,898 @@ /*=================================================================== BlueBerry Platform 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 "berryWorkbenchSourceProvider.h" #include "berryIContextService.h" #include "berryIEditorSite.h" #include "berryIEvaluationContext.h" #include "berryIPartService.h" #include "berryISelectionService.h" #include "berryIShowInSource.h" #include "berryISources.h" #include "berryIWorkbench.h" #include "berryIWorkbenchLocationService.h" #include "berryIWorkbenchPartConstants.h" #include "berryDetachedWindow.h" #include "berryDisplay.h" #include "berryObjectString.h" #include "berryObjects.h" #include "berryShowInContext.h" #include "berryUiUtil.h" #include "berryWorkbench.h" #include "berryWorkbenchWindow.h" #include #include namespace berry { const QList WorkbenchSourceProvider::PROVIDED_SOURCE_NAMES = QList() << ISources::ACTIVE_CURRENT_SELECTION_NAME() << ISources::ACTIVE_EDITOR_ID_NAME() << ISources::ACTIVE_EDITOR_NAME() << ISources::ACTIVE_PART_ID_NAME() << ISources::ACTIVE_PART_NAME() << ISources::ACTIVE_SITE_NAME() << ISources::SHOW_IN_SELECTION() << ISources::SHOW_IN_INPUT() << ISources::ACTIVE_SHELL_NAME() << ISources::ACTIVE_WORKBENCH_WINDOW_NAME() << ISources::ACTIVE_WORKBENCH_WINDOW_SHELL_NAME() << ISources::ACTIVE_WORKBENCH_WINDOW_IS_TOOLBAR_VISIBLE_NAME() << ISources::ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME() << ISources::ACTIVE_WORKBENCH_WINDOW_IS_STATUS_LINE_VISIBLE_NAME() << ISources::ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME(); WorkbenchSourceProvider::WorkbenchSourceProvider() : workbench(nullptr) , lastActiveEditor(nullptr) , lastActivePart(nullptr) , lastActivePartSite(nullptr) , lastShowInInput(nullptr) - , lastEditorInput(nullptr) , display(nullptr) { } void WorkbenchSourceProvider::Initialize(IServiceLocator* locator) { AbstractSourceProvider::Initialize(locator); // this.locator = locator; IWorkbenchLocationService* wls = locator->GetService(); workbench = wls->GetWorkbench(); workbench->AddWindowListener(this); lastWindow = workbench->GetActiveWorkbenchWindow(); display = workbench->GetDisplay(); qApp->installEventFilter(this); } WorkbenchSourceProvider::~WorkbenchSourceProvider() { if (!lastWindow.Expired()) { lastWindow.Lock()->GetSelectionService()->RemoveSelectionListener(this); } workbench->RemoveWindowListener(this); qApp->removeEventFilter(this); HookListener(const_cast(lastActiveWorkbenchWindow.Lock().GetPointer()), nullptr); lastActiveWorkbenchWindow.Reset(); lastActiveWorkbenchWindowShell.Reset(); lastActiveShell.Reset(); lastWindow.Reset(); } QList WorkbenchSourceProvider::GetProvidedSourceNames() const { return PROVIDED_SOURCE_NAMES; } ISourceProvider::StateMapType WorkbenchSourceProvider::GetCurrentState() const { ISourceProvider::StateMapType currentState; UpdateActiveShell(currentState); UpdateActivePart(currentState); UpdateSelection(currentState); return currentState; } void WorkbenchSourceProvider::SelectionChanged(const SmartPointer& /*part*/, const SmartPointer& newSelection) { if (selection == newSelection) return; // we have already handled the change selection = newSelection; LogDebuggingInfo(QString("Selection changed to ") + (selection ? selection->ToString() : QString("nullptr"))); FireSourceChanged(ISources::ACTIVE_CURRENT_SELECTION(), ISources::ACTIVE_CURRENT_SELECTION_NAME(), selection); } int WorkbenchSourceProvider::UpdateSelection(ISourceProvider::StateMapType& currentState) const { int sources = 0; currentState.insert(ISources::ACTIVE_CURRENT_SELECTION_NAME(), IEvaluationContext::UNDEFINED_VARIABLE); Object::ConstPointer object = currentState.value(ISources::ACTIVE_PART_NAME()); if (IWorkbenchPart::ConstPointer part = object.Cast()) { if (part->GetSite().IsNotNull() && part->GetSite()->GetSelectionProvider().IsNotNull()) { sources = ISources::ACTIVE_CURRENT_SELECTION(); ISelection::ConstPointer currentSelection = part->GetSite() ->GetSelectionProvider()->GetSelection(); currentState.insert(ISources::ACTIVE_CURRENT_SELECTION_NAME(), currentSelection); } } return sources; } void WorkbenchSourceProvider::UpdateWindows(IWorkbenchWindow* newWindow) { if (lastWindow == newWindow) { return; } ISelection::ConstPointer selection; if (!lastWindow.Expired()) { lastWindow.Lock()->GetSelectionService()->RemoveSelectionListener(this); } if (newWindow != nullptr) { newWindow->GetSelectionService()->AddSelectionListener(this); selection = newWindow->GetSelectionService()->GetSelection(); } SelectionChanged(IWorkbenchPart::Pointer(nullptr), selection); lastWindow = IWorkbenchWindow::Pointer(newWindow); } void WorkbenchSourceProvider::PartActivated(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::PartBroughtToTop(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::PartClosed(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::PartDeactivated(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::PartOpened(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::WindowActivated(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::WindowClosed(const SmartPointer& window) { if (window.IsNotNull()) { window->GetPartService()->RemovePartListener(this); } CheckActivePart(); } void WorkbenchSourceProvider::WindowDeactivated(const SmartPointer& ) { CheckActivePart(); } void WorkbenchSourceProvider::WindowOpened(const SmartPointer& window) { if (window.IsNotNull()) { window->GetPartService()->AddPartListener(this); } } void WorkbenchSourceProvider::HandleCheck(const SmartPointer& s) { if (s != lastActiveShell.Lock()) { lastActiveShell = s; CheckActivePart(); IWorkbenchWindow* window = nullptr; if (s.IsNotNull()) { if (s->GetData().Cast()) { window = s->GetData().Cast().GetPointer(); } else if (DetachedWindow::Pointer dw = s->GetData().Cast()) { window = dw->GetWorkbenchPage()->GetWorkbenchWindow().GetPointer(); } } UpdateWindows(window); } } void WorkbenchSourceProvider::CheckActivePart() { CheckActivePart(false); } void WorkbenchSourceProvider::CheckActivePart(bool updateShowInSelection) { ISourceProvider::StateMapType currentState; UpdateActivePart(currentState, updateShowInSelection); int sources = 0; // Figure out what was changed. const Object::ConstPointer newActivePart = currentState.value(ISources::ACTIVE_PART_NAME()); if (newActivePart != lastActivePart) { sources |= ISources::ACTIVE_PART(); if (newActivePart != IEvaluationContext::UNDEFINED_VARIABLE) { lastActivePart = newActivePart.Cast().GetPointer(); } else { lastActivePart = nullptr; } } const Object::ConstPointer newActivePartId = currentState.value(ISources::ACTIVE_PART_ID_NAME()); if (lastActivePartId != newActivePartId) { sources |= ISources::ACTIVE_PART_ID(); if (newActivePartId != IEvaluationContext::UNDEFINED_VARIABLE) { lastActivePartId = newActivePartId.Cast(); } else { lastActivePartId = nullptr; } } const Object::ConstPointer newActivePartSite = currentState.value(ISources::ACTIVE_SITE_NAME()); if (newActivePartSite != lastActivePartSite) { sources |= ISources::ACTIVE_SITE(); if (newActivePartSite != IEvaluationContext::UNDEFINED_VARIABLE) { lastActivePartSite = newActivePartSite.Cast().GetPointer(); } else { lastActivePartSite = nullptr; } } const Object::ConstPointer newShowInInput = currentState.value(ISources::SHOW_IN_INPUT()); if (newShowInInput != lastShowInInput) { sources |= ISources::ACTIVE_SITE(); lastShowInInput = newShowInInput.GetPointer(); } if (currentState.value(ISources::SHOW_IN_SELECTION()) != IEvaluationContext::UNDEFINED_VARIABLE) { sources |= ISources::ACTIVE_SITE(); } Object::ConstPointer newActiveEditor = currentState.value(ISources::ACTIVE_EDITOR_NAME()); if (newActiveEditor != lastActiveEditor) { sources |= ISources::ACTIVE_EDITOR(); newActiveEditor = (newActiveEditor == IEvaluationContext::UNDEFINED_VARIABLE ? Object::ConstPointer(nullptr) : newActiveEditor); HookListener(const_cast(lastActiveEditor), const_cast(newActiveEditor.Cast().GetPointer())); lastActiveEditor = newActiveEditor.Cast().GetPointer(); } const Object::ConstPointer newEditorInput = currentState.value(ISources::ACTIVE_EDITOR_INPUT_NAME()); - if (newEditorInput != lastEditorInput) + IEditorInput::ConstPointer lastInput; + if (!lastEditorInput.Expired()) + { + lastInput = lastEditorInput.Lock(); + } + if (newEditorInput != lastInput) { sources |= ISources::ACTIVE_EDITOR(); if (newEditorInput != IEvaluationContext::UNDEFINED_VARIABLE) { - lastEditorInput = newEditorInput.Cast().GetPointer(); + lastEditorInput = newEditorInput.Cast(); } else { - lastEditorInput = nullptr; + lastEditorInput.Reset(); } } + const Object::ConstPointer newActiveEditorId = currentState.value(ISources::ACTIVE_EDITOR_ID_NAME()); if (newActiveEditorId != lastActiveEditorId) { sources |= ISources::ACTIVE_EDITOR_ID(); if (newActiveEditorId != IEvaluationContext::UNDEFINED_VARIABLE) { lastActiveEditorId = newActiveEditorId.Cast(); } else { lastActiveEditorId = nullptr; } } // Fire the event, if something has changed. if (sources != 0) { if (DEBUG) { if ((sources & ISources::ACTIVE_PART()) != 0) { LogDebuggingInfo("Active part changed to " + (lastActivePart ? lastActivePart->ToString() : QString("nullptr"))); } if ((sources & ISources::ACTIVE_PART_ID()) != 0) { LogDebuggingInfo("Active part id changed to " + (lastActivePartId ? lastActivePartId->ToString() : QString("nullptr"))); } if ((sources & ISources::ACTIVE_SITE()) != 0) { LogDebuggingInfo("Active site changed to " + (lastActivePartSite ? lastActivePartSite->ToString() : QString("nullptr"))); } if ((sources & ISources::ACTIVE_EDITOR()) != 0) { LogDebuggingInfo("Active editor changed to " + (lastActiveEditor ? lastActiveEditor->ToString() : QString("nullptr"))); } if ((sources & ISources::ACTIVE_EDITOR_ID()) != 0) { LogDebuggingInfo("Active editor id changed to " + (lastActiveEditorId ? lastActiveEditorId->ToString() : QString("nullptr"))); } } sources |= UpdateSelection(currentState); FireSourceChanged(sources, currentState); } } SmartPointer WorkbenchSourceProvider::GetShowInSource(const SmartPointer& sourcePart) const { IShowInSource::Pointer result(UiUtil::GetAdapter(sourcePart.GetPointer())); return result; } SmartPointer WorkbenchSourceProvider::GetContext(const SmartPointer& sourcePart) const { IShowInSource::Pointer source = GetShowInSource(sourcePart); if (source.IsNotNull()) { ShowInContext::Pointer context = source->GetShowInContext(); if (context.IsNotNull()) { return context; } } else if (IEditorPart::Pointer editorPart = sourcePart.Cast()) { Object::Pointer input = editorPart->GetEditorInput(); ISelectionProvider::Pointer sp = sourcePart->GetSite()->GetSelectionProvider(); ISelection::ConstPointer sel = sp.IsNull() ? ISelection::ConstPointer(nullptr) : sp->GetSelection(); ShowInContext::Pointer context(new ShowInContext(input, sel)); return context; } return ShowInContext::Pointer(nullptr); } IWorkbenchWindow* WorkbenchSourceProvider::GetActiveWindow() const { // IContextService* const contextService = workbench->GetService(); // if (contextService != nullptr) // { // const int shellType = contextService->GetShellType(qApp->activeWindow()); // if (shellType != IContextService::TYPE_DIALOG) // { // return workbench->GetActiveWorkbenchWindow().GetPointer(); // } // } if (qApp->activeWindow() != qApp->activeModalWidget()) { return workbench->GetActiveWorkbenchWindow().GetPointer(); } return nullptr; } void WorkbenchSourceProvider::UpdateActivePart(ISourceProvider::StateMapType& currentState) const { UpdateActivePart(currentState, false); } void WorkbenchSourceProvider::UpdateActivePart(ISourceProvider::StateMapType& currentState, bool updateShowInSelection) const { currentState.insert(ISources::ACTIVE_SITE_NAME(), IEvaluationContext::UNDEFINED_VARIABLE); currentState.insert(ISources::ACTIVE_PART_NAME(), IEvaluationContext::UNDEFINED_VARIABLE); currentState.insert(ISources::ACTIVE_PART_ID_NAME(), IEvaluationContext::UNDEFINED_VARIABLE); currentState.insert(ISources::ACTIVE_EDITOR_NAME(), IEvaluationContext::UNDEFINED_VARIABLE); currentState.insert(ISources::ACTIVE_EDITOR_ID_NAME(), IEvaluationContext::UNDEFINED_VARIABLE); currentState.insert(ISources::SHOW_IN_INPUT(), IEvaluationContext::UNDEFINED_VARIABLE); currentState.insert(ISources::SHOW_IN_SELECTION(), IEvaluationContext::UNDEFINED_VARIABLE); IWorkbenchWindow* const activeWorkbenchWindow = GetActiveWindow(); if (activeWorkbenchWindow != nullptr) { const IWorkbenchPage::Pointer activeWorkbenchPage = activeWorkbenchWindow->GetActivePage(); if (activeWorkbenchPage.IsNotNull()) { // Check the active workbench part. const IWorkbenchPart::Pointer newActivePart = activeWorkbenchPage->GetActivePart(); currentState.insert(ISources::ACTIVE_PART_NAME(), newActivePart); if (newActivePart.IsNotNull()) { const IWorkbenchPartSite::Pointer activeWorkbenchPartSite = newActivePart->GetSite(); currentState.insert(ISources::ACTIVE_SITE_NAME(), activeWorkbenchPartSite); if (activeWorkbenchPartSite.IsNotNull()) { const Object::Pointer newActivePartId(new ObjectString(activeWorkbenchPartSite->GetId())); currentState.insert(ISources::ACTIVE_PART_ID_NAME(), newActivePartId); } ShowInContext::Pointer context = GetContext(newActivePart); if (context.IsNotNull()) { const Object::Pointer input = context->GetInput(); if (input.IsNotNull()) { currentState.insert(ISources::SHOW_IN_INPUT(), input); } if (updateShowInSelection) { const ISelection::ConstPointer selection = context->GetSelection(); if (selection.IsNotNull()) { currentState.insert(ISources::SHOW_IN_SELECTION(), selection); } } } } // Check the active editor part. const IEditorPart::Pointer newActiveEditor = activeWorkbenchPage->GetActiveEditor(); currentState.insert(ISources::ACTIVE_EDITOR_NAME(), newActiveEditor); if (newActiveEditor.IsNotNull()) { currentState.insert(ISources::ACTIVE_EDITOR_INPUT_NAME(), newActiveEditor->GetEditorInput()); const IEditorSite::Pointer activeEditorSite = newActiveEditor->GetEditorSite(); if (activeEditorSite.IsNotNull()) { const Object::Pointer newActiveEditorId(new ObjectString(activeEditorSite->GetId())); currentState.insert(ISources::ACTIVE_EDITOR_ID_NAME(), newActiveEditorId); } } } } } /** * The listener to individual window properties. */ void WorkbenchSourceProvider::PropertyChange(const SmartPointer& event) { if (WorkbenchWindow::PROP_TOOLBAR_VISIBLE == event->GetProperty()) { const Object::Pointer newValue = event->GetNewValue(); if (newValue.IsNull() || !(newValue.Cast())) return; if (lastToolbarVisibility != newValue) { FireSourceChanged( ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(), ISources::ACTIVE_WORKBENCH_WINDOW_IS_TOOLBAR_VISIBLE_NAME(), newValue); lastToolbarVisibility = newValue.Cast(); } } else if (WorkbenchWindow::PROP_PERSPECTIVEBAR_VISIBLE == event->GetProperty()) { const Object::Pointer newValue = event->GetNewValue(); if (newValue.IsNull() || !(newValue.Cast())) return; if (lastPerspectiveBarVisibility != newValue) { FireSourceChanged( ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(), ISources::ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME(), newValue); lastPerspectiveBarVisibility = newValue.Cast(); } } else if (WorkbenchWindow::PROP_STATUS_LINE_VISIBLE == event->GetProperty()) { const Object::Pointer newValue = event->GetNewValue(); if (newValue.IsNull() || !(newValue.Cast())) return; if (lastStatusLineVisibility != newValue) { FireSourceChanged( ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(), ISources::ACTIVE_WORKBENCH_WINDOW_IS_STATUS_LINE_VISIBLE_NAME(), newValue); lastStatusLineVisibility = newValue.Cast(); } } else { IPropertyChangeListener::PropertyChange(event); } } void WorkbenchSourceProvider::PerspectiveActivated(const SmartPointer& /*page*/, const SmartPointer& perspective) { QString id = perspective.IsNull() ? QString() : perspective->GetId(); if (lastPerspectiveId.IsNotNull() && *lastPerspectiveId == id) { return; } Object::Pointer newValue(new ObjectString(id)); FireSourceChanged(ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(), ISources::ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME(), newValue); lastPerspectiveId = new ObjectString(id); } void WorkbenchSourceProvider::PerspectiveChanged(const SmartPointer& /*page*/, const SmartPointer& /*perspective*/, const QString& /*changeId*/) { } void WorkbenchSourceProvider::PropertyChange(const Object::Pointer& source, int propId) { if (propId == IWorkbenchPartConstants::PROP_INPUT) { HandleInputChanged(source.Cast()); } } bool WorkbenchSourceProvider::eventFilter(QObject* /*obj*/, QEvent *event) { if (event->type() == QEvent::WindowActivate) HandleShellEvent(); return false; } void WorkbenchSourceProvider::HandleShellEvent() { // if (!(event.widget instanceof Shell)) // { // if (DEBUG) // { // logDebuggingInfo("WSP: passOnEvent: " + event.widget); //$NON-NLS-1$ // } // return; // } LogDebuggingInfo("\tWSP:lastActiveShell: " + (!lastActiveShell.Expired() ? lastActiveShell.Lock()->GetControl()->objectName() : QString("nullptr"))); LogDebuggingInfo("\tWSP:lastActiveWorkbenchWindowShell: " + (!lastActiveWorkbenchWindowShell.Expired() ? lastActiveWorkbenchWindowShell.Lock()->GetControl()->objectName() : QString("nullptr"))); const ISourceProvider::StateMapType currentState = GetCurrentState(); const Shell::ConstPointer newActiveShell = currentState.value(ISources::ACTIVE_SHELL_NAME()).Cast(); const WorkbenchWindow::ConstPointer newActiveWorkbenchWindow = currentState.value(ISources::ACTIVE_WORKBENCH_WINDOW_NAME()).Cast(); const Shell::ConstPointer newActiveWorkbenchWindowShell = currentState.value(ISources::ACTIVE_WORKBENCH_WINDOW_SHELL_NAME()).Cast(); // dont update the coolbar/perspective bar visibility unless we're // processing a workbench window change const ObjectBool::ConstPointer newToolbarVisibility( newActiveWorkbenchWindow.IsNull() ? lastToolbarVisibility.GetPointer() : (newActiveWorkbenchWindow->GetToolBarVisible() ? new ObjectBool(true) : new ObjectBool(false))); const ObjectBool::ConstPointer newPerspectiveBarVisibility( newActiveWorkbenchWindow.IsNull() ? lastPerspectiveBarVisibility.GetPointer() : (newActiveWorkbenchWindow->GetPerspectiveBarVisible() ? new ObjectBool(true) : new ObjectBool(false))); const ObjectBool::ConstPointer newStatusLineVis( newActiveWorkbenchWindow.IsNull() ? lastStatusLineVisibility.GetPointer() : (newActiveWorkbenchWindow->GetStatusLineVisible() ? new ObjectBool(true) : new ObjectBool(false))); ObjectString::ConstPointer perspectiveId = lastPerspectiveId; if (newActiveWorkbenchWindow.IsNotNull()) { IWorkbenchPage::Pointer activePage = newActiveWorkbenchWindow->GetActivePage(); if (activePage.IsNotNull()) { IPerspectiveDescriptor::Pointer perspective = activePage->GetPerspective(); if (perspective.IsNotNull()) { perspectiveId = new ObjectString(perspective->GetId()); } } } // Figure out which variables have changed. const bool shellChanged = newActiveShell != lastActiveShell.Lock(); const bool windowChanged = newActiveWorkbenchWindowShell != lastActiveWorkbenchWindowShell.Lock(); const bool toolbarChanged = newToolbarVisibility != lastToolbarVisibility; const bool statusLineChanged = newStatusLineVis != lastStatusLineVisibility; const bool perspectiveBarChanged = newPerspectiveBarVisibility != lastPerspectiveBarVisibility; const bool perspectiveIdChanged = lastPerspectiveId != perspectiveId; // Fire an event for those sources that have changed. if (shellChanged && windowChanged) { ISourceProvider::StateMapType sourceValuesByName; sourceValuesByName.insert(ISources::ACTIVE_SHELL_NAME(), newActiveShell); sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_NAME(), newActiveWorkbenchWindow); sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_SHELL_NAME(), newActiveWorkbenchWindowShell); int sourceFlags = ISources::ACTIVE_SHELL() | ISources::ACTIVE_WORKBENCH_WINDOW(); if (toolbarChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_TOOLBAR_VISIBLE_NAME(), newToolbarVisibility); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (statusLineChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_STATUS_LINE_VISIBLE_NAME(), newStatusLineVis); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (perspectiveBarChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME(), newPerspectiveBarVisibility); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (perspectiveIdChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME(), perspectiveId); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (DEBUG) { LogDebuggingInfo("Active shell changed to " + (newActiveShell ? newActiveShell->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window changed to " + (newActiveWorkbenchWindow ? newActiveWorkbenchWindow->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window shell changed to " + (newActiveWorkbenchWindowShell ? newActiveWorkbenchWindowShell->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window coolbar visibility " + (newToolbarVisibility ? newToolbarVisibility->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window perspective bar visibility " + (newPerspectiveBarVisibility ? newPerspectiveBarVisibility->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window status line visibility " + (newStatusLineVis ? newStatusLineVis->ToString() : QString("nullptr"))); } FireSourceChanged(sourceFlags, sourceValuesByName); HookListener(const_cast(lastActiveWorkbenchWindow.Lock().GetPointer()), const_cast(newActiveWorkbenchWindow.GetPointer())); } else if (shellChanged) { LogDebuggingInfo("Active shell changed to " + (newActiveShell ? newActiveShell->ToString() : QString("nullptr"))); FireSourceChanged(ISources::ACTIVE_SHELL(), ISources::ACTIVE_SHELL_NAME(), newActiveShell); } else if (windowChanged) { ISourceProvider::StateMapType sourceValuesByName; sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_NAME(), newActiveWorkbenchWindow); sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_SHELL_NAME(), newActiveWorkbenchWindowShell); int sourceFlags = ISources::ACTIVE_SHELL() | ISources::ACTIVE_WORKBENCH_WINDOW(); if (toolbarChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_TOOLBAR_VISIBLE_NAME(), newToolbarVisibility); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (statusLineChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_STATUS_LINE_VISIBLE_NAME(), newStatusLineVis); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (perspectiveBarChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME(), newPerspectiveBarVisibility); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (perspectiveIdChanged) { sourceValuesByName.insert(ISources::ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME(), perspectiveId); sourceFlags |= ISources::ACTIVE_WORKBENCH_WINDOW_SUBORDINATE(); } if (DEBUG) { LogDebuggingInfo("Active workbench window changed to " + (newActiveWorkbenchWindow ? newActiveWorkbenchWindow->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window shell changed to " + (newActiveWorkbenchWindowShell ? newActiveWorkbenchWindowShell->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window coolbar visibility " + (newToolbarVisibility ? newToolbarVisibility->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window perspective bar visibility " + (newPerspectiveBarVisibility ? newPerspectiveBarVisibility->ToString() : QString("nullptr"))); LogDebuggingInfo("Active workbench window status line visibility " + (newStatusLineVis ? newStatusLineVis->ToString() : QString("nullptr"))); } FireSourceChanged(sourceFlags, sourceValuesByName); HookListener(const_cast(lastActiveWorkbenchWindow.Lock().GetPointer()), const_cast(newActiveWorkbenchWindow.GetPointer())); } if (shellChanged || windowChanged) { CheckOtherSources(newActiveShell); } // Update the member variables. lastActiveShell = newActiveShell; lastActiveWorkbenchWindowShell = newActiveWorkbenchWindowShell; lastActiveWorkbenchWindow = newActiveWorkbenchWindow; lastToolbarVisibility = newToolbarVisibility; lastStatusLineVisibility = newStatusLineVis; lastPerspectiveBarVisibility = newPerspectiveBarVisibility; lastPerspectiveId = perspectiveId; } void WorkbenchSourceProvider::CheckOtherSources(const SmartPointer& s) { HandleCheck(s); } void WorkbenchSourceProvider::HandleInputChanged(const SmartPointer& editor) { IEditorInput::Pointer newInput = editor->GetEditorInput(); - if (newInput != lastEditorInput) + IEditorInput::ConstPointer lastInput; + if (!lastEditorInput.Expired()) + { + lastInput = lastEditorInput.Lock(); + } + if (newInput != lastInput) { FireSourceChanged(ISources::ACTIVE_EDITOR(), ISources::ACTIVE_EDITOR_INPUT_NAME(), newInput.IsNull() ? IEvaluationContext::UNDEFINED_VARIABLE : Object::ConstPointer(newInput)); - lastEditorInput = newInput.GetPointer(); + lastEditorInput = newInput; } } void WorkbenchSourceProvider::HookListener(WorkbenchWindow* lastActiveWorkbenchWindow, WorkbenchWindow* newActiveWorkbenchWindow) { if (lastActiveWorkbenchWindow != nullptr) { lastActiveWorkbenchWindow->RemovePropertyChangeListener(this); lastActiveWorkbenchWindow->RemovePerspectiveListener(this); } if (newActiveWorkbenchWindow != nullptr) { newActiveWorkbenchWindow->AddPropertyChangeListener(this); newActiveWorkbenchWindow->AddPerspectiveListener(this); } } void WorkbenchSourceProvider::HookListener(IEditorPart* lastActiveEditor, IEditorPart* newActiveEditor) { if (lastActiveEditor != nullptr) { lastActiveEditor->RemovePropertyListener(this); } if (newActiveEditor != nullptr) { newActiveEditor->AddPropertyListener(this); } } void WorkbenchSourceProvider::UpdateActiveShell(ISourceProvider::StateMapType& currentState) const { QVariant windowShell; QWidget* activeWindow = qApp->activeWindow(); if (activeWindow) { windowShell = activeWindow->property("shell"); } Shell::Pointer newActiveShell(windowShell.isValid() ? windowShell.value() : nullptr); currentState.insert(ISources::ACTIVE_SHELL_NAME(), newActiveShell); /* * We will fallback to the workbench window, but only if a dialog is not * open. */ // IContextService* const contextService = workbench->GetService(); // const int shellType = contextService->GetShellType(newActiveShell); // if (shellType == IContextService::TYPE_DIALOG) // return; if (activeWindow == qApp->activeModalWidget()) return; const WorkbenchWindow::ConstPointer newActiveWorkbenchWindow = workbench->GetActiveWorkbenchWindow().Cast(); Shell::Pointer newActiveWorkbenchWindowShell; if (newActiveWorkbenchWindow.IsNotNull()) { newActiveWorkbenchWindowShell = newActiveWorkbenchWindow->GetShell(); } currentState.insert(ISources::ACTIVE_WORKBENCH_WINDOW_NAME(), newActiveWorkbenchWindow); currentState.insert(ISources::ACTIVE_WORKBENCH_WINDOW_SHELL_NAME(), newActiveWorkbenchWindowShell); const ObjectBool::ConstPointer newToolbarVisibility( newActiveWorkbenchWindow.IsNull() ? lastToolbarVisibility.GetPointer() : (newActiveWorkbenchWindow->GetToolBarVisible() ? new ObjectBool(true) : new ObjectBool(false))); const ObjectBool::ConstPointer newPerspectiveBarVisibility( newActiveWorkbenchWindow.IsNull() ? lastPerspectiveBarVisibility.GetPointer() : (newActiveWorkbenchWindow->GetPerspectiveBarVisible() ? new ObjectBool(true) : new ObjectBool(false))); const ObjectBool::ConstPointer newStatusLineVis( newActiveWorkbenchWindow.IsNull() ? lastStatusLineVisibility.GetPointer() : (newActiveWorkbenchWindow->GetStatusLineVisible() ? new ObjectBool(true) : new ObjectBool(false))); ObjectString::ConstPointer perspectiveId = lastPerspectiveId; if (newActiveWorkbenchWindow.IsNotNull()) { const IWorkbenchPage::Pointer activePage = newActiveWorkbenchWindow->GetActivePage(); if (activePage.IsNotNull()) { const IPerspectiveDescriptor::Pointer perspective = activePage->GetPerspective(); if (perspective.IsNotNull()) { perspectiveId = new ObjectString(perspective->GetId()); } } } currentState.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_TOOLBAR_VISIBLE_NAME(), newToolbarVisibility); currentState.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME(), newPerspectiveBarVisibility); currentState.insert(ISources::ACTIVE_WORKBENCH_WINDOW_IS_STATUS_LINE_VISIBLE_NAME(), newStatusLineVis); currentState.insert(ISources::ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME(), perspectiveId); } IPartListener::Events::Types WorkbenchSourceProvider::GetPartEventTypes() const { return IPartListener::Events::ACTIVATED | IPartListener::Events::BROUGHT_TO_TOP | IPartListener::Events::CLOSED | IPartListener::Events::DEACTIVATED | IPartListener::Events::OPENED; } IPerspectiveListener::Events::Types WorkbenchSourceProvider::GetPerspectiveEventTypes() const { return IPerspectiveListener::Events::ACTIVATED | IPerspectiveListener::Events::CHANGED; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.h b/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.h index 6bd5fbf525..3959b77be0 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchSourceProvider.h @@ -1,243 +1,243 @@ /*=================================================================== BlueBerry Platform 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 BERRYWORKBENCHSOURCEPROVIDER_H #define BERRYWORKBENCHSOURCEPROVIDER_H #include "berryAbstractSourceProvider.h" #include "berryINullSelectionListener.h" #include "berryIPartListener.h" #include "berryIWindowListener.h" #include "berryIPropertyChangeListener.h" #include "berryIPerspectiveListener.h" #include "berryIShellListener.h" namespace berry { struct IEditorPart; struct IEditorInput; struct IShowInSource; class Display; class ObjectBool; class ObjectString; class ShowInContext; class WorkbenchWindow; class WorkbenchSourceProvider : public QObject, public AbstractSourceProvider, private INullSelectionListener, private IPartListener, private IWindowListener, private IPropertyChangeListener, private IPerspectiveListener { Q_OBJECT Q_INTERFACES(berry::ISourceProvider) private: /** * The names of the sources supported by this source provider. */ static const QList PROVIDED_SOURCE_NAMES; IWorkbench* workbench; WeakPointer lastWindow; // private IServiceLocator locator; // Selection SourceProvider SmartPointer selection; public: berryObjectMacro(berry::WorkbenchSourceProvider) WorkbenchSourceProvider(); void Initialize(IServiceLocator* locator) override; ~WorkbenchSourceProvider() override; QList GetProvidedSourceNames() const override; ISourceProvider::StateMapType GetCurrentState() const override; private: void SelectionChanged(const SmartPointer& part, const SmartPointer& newSelection) override; int UpdateSelection(ISourceProvider::StateMapType& currentState) const; void UpdateWindows(IWorkbenchWindow* newWindow); // Active Part SourceProvider /** * The last active editor part seen as active by this provider. This value * may be null if there is no currently active editor. */ const IEditorPart* lastActiveEditor; /** * The last active editor id seen as active by this provider. This value may * be null if there is no currently active editor. */ SmartPointer lastActiveEditorId; /** * The last active part seen as active by this provider. This value may be * null if there is no currently active part. */ const IWorkbenchPart* lastActivePart; /** * The last active part id seen as active by this provider. This value may * be null if there is no currently active part. */ SmartPointer lastActivePartId; /** * The last active part site seen by this provider. This value may be * null if there is no currently active site. */ const IWorkbenchPartSite* lastActivePartSite; SmartPointer lastShowInInput; void PartActivated(const SmartPointer& part) override; void PartBroughtToTop(const SmartPointer& part) override; void PartClosed(const SmartPointer& part) override; void PartDeactivated(const SmartPointer& part) override; void PartOpened(const SmartPointer& part) override; void WindowActivated(const SmartPointer& window) override; void WindowClosed(const SmartPointer& window) override; void WindowDeactivated(const SmartPointer& window) override; void WindowOpened(const SmartPointer& window) override; - const IEditorInput* lastEditorInput; + WeakPointer lastEditorInput; void HandleCheck(const SmartPointer& s); void CheckActivePart(); void CheckActivePart(bool updateShowInSelection); SmartPointer GetShowInSource(const SmartPointer& sourcePart) const; SmartPointer GetContext(const SmartPointer& sourcePart) const; IWorkbenchWindow* GetActiveWindow() const; void UpdateActivePart(ISourceProvider::StateMapType& currentState) const; void UpdateActivePart(ISourceProvider::StateMapType& currentState, bool updateShowInSelection) const; // Active Part SourceProvider /** * The display on which this provider is working. */ Display* display; /** * The last shell seen as active by this provider. This value may be * null if the last call to * Display.getActiveShell() returned null. */ WeakPointer lastActiveShell; /** * The last workbench window shell seen as active by this provider. This * value may be null if the last call to * workbench.getActiveWorkbenchWindow() returned * null. */ WeakPointer lastActiveWorkbenchWindowShell; /** * The last workbench window seen as active by this provider. This value may * be null if the last call to * workbench.getActiveWorkbenchWindow() returned * null. */ WeakPointer lastActiveWorkbenchWindow; /** * The result of the last visibility check on the toolbar of the last active * workbench window. */ SmartPointer lastToolbarVisibility; /** * The result of the last visibility check on the perspective bar of the * last active workbench window. */ SmartPointer lastPerspectiveBarVisibility; /** * The result of the last visibility check on the status line for the last * workbench window. */ SmartPointer lastStatusLineVisibility; /** * The last perspective id that was provided by this source. */ SmartPointer lastPerspectiveId; /** * The listener to individual window properties. */ void PropertyChange(const SmartPointer& event) override; void PropertyChange(const Object::Pointer& source, int propId) override; void PerspectiveActivated(const SmartPointer& page, const SmartPointer& perspective) override; using IPerspectiveListener::PerspectiveChanged; void PerspectiveChanged(const SmartPointer& page, const SmartPointer& perspective, const QString& changeId) override; bool eventFilter(QObject *obj, QEvent *event) override; /** * The listener to shell activations on the display. * Notifies all listeners that the source has changed. */ void HandleShellEvent(); void CheckOtherSources(const SmartPointer& s); void HandleInputChanged(const SmartPointer& editor); void HookListener(WorkbenchWindow* lastActiveWorkbenchWindow, WorkbenchWindow* newActiveWorkbenchWindow); void HookListener(IEditorPart* lastActiveEditor, IEditorPart* newActiveEditor); void UpdateActiveShell(ISourceProvider::StateMapType& currentState) const; IPartListener::Events::Types GetPartEventTypes() const override; IPerspectiveListener::Events::Types GetPerspectiveEventTypes() const override; }; } #endif // BERRYWORKBENCHSOURCEPROVIDER_H diff --git a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPartListener.h b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPartListener.h index afd7f19561..8f72eb2cb5 100644 --- a/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPartListener.h +++ b/Plugins/org.mitk.gui.common/src/mitkIRenderWindowPartListener.h @@ -1,60 +1,65 @@ /*=================================================================== 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 MITKIRENDERWINDOWPARTLISTENER_H #define MITKIRENDERWINDOWPARTLISTENER_H #include namespace mitk { -struct IRenderWindowPart; - -/** - * \ingroup org_mitk_gui_common - * - * \brief Interface for berry::IViewPart implementations to be notified about mitk::IRenderWindowPart lifecycle changes. - * - * This interface is intended to be implemented by subclasses of berry::IWorkbenchPart. If implemented, - * the interface methods are called automatically if a Workbench part which implementes mitk::IRenderWindowPart - * is activated or deactivated. - * - * The notion of activated and deactivated is slightly different from the usual Workbench part lifecycle. - */ -struct MITK_GUI_COMMON_PLUGIN IRenderWindowPartListener -{ - virtual ~IRenderWindowPartListener(); + struct IRenderWindowPart; /** - * Called when a IRenderWindowPart is activated or if it becomes visible and no - * other IRenderWindowPart was activated before. + * \ingroup org_mitk_gui_common * - * \param renderWindowPart The newly activated IRenderWindowPart. - */ - virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) = 0; - - /** - * Called when a IRenderWindowPart becomes invisible and if it was active before. + * \brief Interface for berry::IViewPart implementations to be notified about mitk::IRenderWindowPart lifecycle changes. * - * \param renderWindowPart The deactivated IRenderWindowPart. + * This interface is intended to be implemented by subclasses of berry::IWorkbenchPart. If implemented, + * the interface methods are called automatically if a Workbench part which implementes mitk::IRenderWindowPart + * is activated or deactivated. + * + * The notion of activated and deactivated is slightly different from the usual Workbench part lifecycle. */ - virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) = 0; -}; + struct MITK_GUI_COMMON_PLUGIN IRenderWindowPartListener + { + virtual ~IRenderWindowPartListener(); + + /** + * Called when an IRenderWindowPart is activated or if it becomes visible and no + * other IRenderWindowPart was activated before. + * + * \param renderWindowPart The newly activated IRenderWindowPart. + */ + virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) = 0; + + /** + * Called when an IRenderWindowPart becomes invisible and if it was active before. + * + * \param renderWindowPart The deactivated IRenderWindowPart. + */ + virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) = 0; + /** + * Called when an IRenderWindowPart changes and if it was active before. + * + * \param renderWindowPart The modified IRenderWindowPart. + */ + virtual void RenderWindowPartInputChanged(mitk::IRenderWindowPart* /*renderWindowPart*/) {}; + }; } #endif // MITKIRENDERWINDOWPARTLISTENER_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.cpp index c698df6511..5e3d31bc27 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.cpp @@ -1,110 +1,124 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkIRenderWindowPart.h" // mitk gui common plugin #include // berry #include QList AbstractDataNodeAction::GetSelectedNodes(berry::IWorkbenchPartSite::Pointer workbenchPartSite) { QList selectedNodes; if (workbenchPartSite.IsNull()) { return selectedNodes; } berry::ISelection::ConstPointer selection = workbenchPartSite->GetWorkbenchWindow()->GetSelectionService()->GetSelection(); mitk::DataNodeSelection::ConstPointer currentSelection = selection.Cast(); if (currentSelection.IsNull() || currentSelection->IsEmpty()) { return selectedNodes; } selectedNodes = QList::fromStdList(currentSelection->GetSelectedDataNodes()); return selectedNodes; } QmitkAbstractDataNodeAction::QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer workbenchPartSite) { m_WorkbenchPartSite = workbenchPartSite; } QmitkAbstractDataNodeAction::QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite* workbenchPartSite) { m_WorkbenchPartSite = berry::IWorkbenchPartSite::Pointer(workbenchPartSite); } -QmitkAbstractDataNodeAction::~QmitkAbstractDataNodeAction() -{ - // nothing here -} - void QmitkAbstractDataNodeAction::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage m_DataStorage = dataStorage; } } void QmitkAbstractDataNodeAction::SetSelectedNodes(const QList& selectedNodes) { m_SelectedNodes = selectedNodes; // use the first selected node to initialize the data node actions InitializeWithDataNode(m_SelectedNodes.front()); } +void QmitkAbstractDataNodeAction::SetBaseRenderer(mitk::BaseRenderer* baseRenderer) +{ + if (m_BaseRenderer != baseRenderer) + { + // set the new base renderer + m_BaseRenderer = baseRenderer; + } +} + +mitk::BaseRenderer::Pointer QmitkAbstractDataNodeAction::GetBaseRenderer() +{ + mitk::BaseRenderer::Pointer baseRenderer; + if (!m_BaseRenderer.IsExpired()) + { + baseRenderer = m_BaseRenderer.Lock(); + } + return baseRenderer; +} + QList QmitkAbstractDataNodeAction::GetSelectedNodes() const { if (!m_SelectedNodes.isEmpty()) { return m_SelectedNodes; } if (m_WorkbenchPartSite.Expired()) { // return empty list of selected nodes return m_SelectedNodes; } // retrieve selection from the workbench selection service return AbstractDataNodeAction::GetSelectedNodes(m_WorkbenchPartSite.Lock()); } mitk::DataNode::Pointer QmitkAbstractDataNodeAction::GetSelectedNode() const { QList selectedNodes = GetSelectedNodes(); if (selectedNodes.empty()) { return nullptr; } // no batch action; should only be called with a single node mitk::DataNode::Pointer dataNode = selectedNodes.front(); if (nullptr == dataNode) { return nullptr; } return dataNode; } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.h index 72f0763b5c..b259da9abc 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkAbstractDataNodeAction.h @@ -1,64 +1,75 @@ /*=================================================================== 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 QMITKABSTRACTDATANODEACTION_H #define QMITKABSTRACTDATANODEACTION_H #include // mitk core +#include #include #include // berry #include // qt #include namespace AbstractDataNodeAction { MITK_QT_APP QList GetSelectedNodes(berry::IWorkbenchPartSite::Pointer workbenchPartSite); } class MITK_QT_APP QmitkAbstractDataNodeAction { public: QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkAbstractDataNodeAction(); - void SetDataStorage(mitk::DataStorage* dataStorage); void SetSelectedNodes(const QList& selectedNodes); + void SetBaseRenderer(mitk::BaseRenderer* baseRenderer); virtual void InitializeWithDataNode(const mitk::DataNode*) { } protected: virtual void InitializeAction() = 0; + + /** + * @brief Grants access to the base renderer stored for the action. + * Will return nullptr if renderer was never set or has become invalid + */ + mitk::BaseRenderer::Pointer GetBaseRenderer(); + mitk::DataNode::Pointer GetSelectedNode() const; QList GetSelectedNodes() const; berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite; mitk::WeakPointer m_DataStorage; QList m_SelectedNodes; +private: + + mitk::WeakPointer m_BaseRenderer; + }; #endif // QMITKABSTRACTDATANODEACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.cpp index 4f639cc723..66ab598b86 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.cpp @@ -1,135 +1,141 @@ /*=================================================================== 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 // qt #include #include #include QmitkDataNodeColorAction::QmitkDataNodeColorAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QWidgetAction(parent) , QmitkAbstractDataNodeAction(workbenchPartSite) { InitializeAction(); } QmitkDataNodeColorAction::QmitkDataNodeColorAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QWidgetAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { InitializeAction(); } -QmitkDataNodeColorAction::~QmitkDataNodeColorAction() -{ - // nothing here -} - void QmitkDataNodeColorAction::InitializeAction() { m_ColorButton = new QPushButton; m_ColorButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); connect(m_ColorButton, &QPushButton::clicked, this, &QmitkDataNodeColorAction::OnColorChanged); QLabel* colorLabel = new QLabel(tr("Color: ")); colorLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QHBoxLayout* colorWidgetLayout = new QHBoxLayout; colorWidgetLayout->setContentsMargins(4, 4, 4, 4); colorWidgetLayout->addWidget(colorLabel); colorWidgetLayout->addWidget(m_ColorButton); QWidget* colorWidget = new QWidget; colorWidget->setLayout(colorWidgetLayout); setDefaultWidget(colorWidget); connect(this, &QmitkDataNodeColorAction::changed, this, &QmitkDataNodeColorAction::OnActionChanged); } void QmitkDataNodeColorAction::InitializeWithDataNode(const mitk::DataNode* dataNode) { + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + float rgb[3]; - if (dataNode->GetColor(rgb)) + if (dataNode->GetColor(rgb, baseRenderer)) { QColor color(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255); QString styleSheet = QString("background-color: ") + color.name(QColor::HexRgb); m_ColorButton->setAutoFillBackground(true); m_ColorButton->setStyleSheet(styleSheet); } } void QmitkDataNodeColorAction::OnColorChanged() { - bool selectedColor = false; - QColor newColor; - - auto selectedNodes = GetSelectedNodes(); - if (selectedNodes.isEmpty()) + auto dataNodes = GetSelectedNodes(); + if (dataNodes.isEmpty()) { return; } - for (auto& dataNode : selectedNodes) + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + + bool selectedColor = false; + QColor newColor; + + for (auto& dataNode : dataNodes) { if (dataNode.IsNull()) { continue; } float rgb[3]; - if (dataNode->GetColor(rgb)) + if (dataNode->GetColor(rgb, baseRenderer)) { if (!selectedColor) { QColor initial(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255); newColor = QColorDialog::getColor(initial, nullptr, QString(tr("Change color"))); if (newColor.isValid()) { selectedColor = true; } else { return; } } - dataNode->SetProperty("color", mitk::ColorProperty::New(newColor.redF(), newColor.greenF(), newColor.blueF())); - if (dataNode->GetProperty("binaryimage.selectedcolor")) + dataNode->SetProperty("color", mitk::ColorProperty::New(newColor.redF(), newColor.greenF(), newColor.blueF()), baseRenderer); + if (dataNode->GetProperty("binaryimage.selectedcolor", baseRenderer)) { - dataNode->SetProperty("binaryimage.selectedcolor", mitk::ColorProperty::New(newColor.redF(), newColor.greenF(), newColor.blueF())); + dataNode->SetProperty("binaryimage.selectedcolor", mitk::ColorProperty::New(newColor.redF(), newColor.greenF(), newColor.blueF()), baseRenderer); } } } - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } void QmitkDataNodeColorAction::OnActionChanged() { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } InitializeWithDataNode(dataNode); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.h index 3ccf8ca703..cb002c535c 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorAction.h @@ -1,56 +1,54 @@ /*=================================================================== 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 QMITKDATANODECOLORACTION_H #define QMITKDATANODECOLORACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include #include class MITK_QT_APP QmitkDataNodeColorAction : public QWidgetAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeColorAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeColorAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeColorAction() override; - virtual void InitializeWithDataNode(const mitk::DataNode* dataNode) override; private Q_SLOTS: void OnColorChanged(); void OnActionChanged(); protected: virtual void InitializeAction() override; private: QPushButton* m_ColorButton; }; #endif // QMITKDATANODECOLORACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.cpp index 18fcb12e2c..46da8c754f 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.cpp @@ -1,158 +1,162 @@ /*=================================================================== 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 #include #include #include #include // mitk gui common plugin #include // qt #include QmitkDataNodeColorMapAction::QmitkDataNodeColorMapAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Colormap")); InitializeAction(); } QmitkDataNodeColorMapAction::QmitkDataNodeColorMapAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Colormap")); InitializeAction(); } -QmitkDataNodeColorMapAction::~QmitkDataNodeColorMapAction() -{ - // nothing here -} - void QmitkDataNodeColorMapAction::InitializeAction() { setCheckable(true); setMenu(new QMenu); connect(menu(), &QMenu::aboutToShow, this, &QmitkDataNodeColorMapAction::OnMenuAboutShow); } void QmitkDataNodeColorMapAction::OnMenuAboutShow() { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } - mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(dataNode->GetProperty("LookupTable")); + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + + mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(dataNode->GetProperty("LookupTable", baseRenderer)); if (lookupTableProperty.IsNull()) { mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); lookupTableProperty = mitk::LookupTableProperty::New(); lookupTableProperty->SetLookupTable(mitkLut); - dataNode->SetProperty("LookupTable", lookupTableProperty); + dataNode->SetProperty("LookupTable", lookupTableProperty, baseRenderer); } mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (lookupTable.IsNull()) { return; } menu()->clear(); - QAction* tmp; - - int i = 0; - std::string lutType = lookupTable->typenameList[i]; - - while (lutType != "END_OF_ARRAY") + QAction* lutAction; + for (const auto& lutTypeString : lookupTable->typenameList) { - tmp = menu()->addAction(QString::fromStdString(lutType)); - tmp->setCheckable(true); + lutAction = menu()->addAction(QString::fromStdString(lutTypeString)); + lutAction->setCheckable(true); - if (lutType == lookupTable->GetActiveTypeAsString()) + if (lutTypeString == lookupTable->GetActiveTypeAsString()) { - tmp->setChecked(true); + lutAction->setChecked(true); } - connect(tmp, &QAction::triggered, this, &QmitkDataNodeColorMapAction::OnActionTriggered); - - lutType = lookupTable->typenameList[++i]; + connect(lutAction, &QAction::triggered, this, &QmitkDataNodeColorMapAction::OnActionTriggered); } } void QmitkDataNodeColorMapAction::OnActionTriggered(bool /*checked*/) { + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + auto selectedNodes = GetSelectedNodes(); for (auto& dataNode : selectedNodes) { if (dataNode.IsNull()) { continue; } - mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(dataNode->GetProperty("LookupTable")); + mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(dataNode->GetProperty("LookupTable", baseRenderer)); if (lookupTableProperty.IsNull()) { continue; } mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (lookupTable.IsNull()) { continue; } + mitk::LookupTable::Pointer renderWindowSpecificLutTab = lookupTable->Clone(); + QAction* senderAction = qobject_cast(QObject::sender()); if (nullptr == senderAction) { continue; } + // set lookup table type defined by the action string std::string activatedItem = senderAction->text().toStdString(); - lookupTable->SetType(activatedItem); - lookupTableProperty->SetValue(lookupTable); + renderWindowSpecificLutTab->SetType(activatedItem); + dataNode->SetProperty("LookupTable", mitk::LookupTableProperty::New(renderWindowSpecificLutTab), baseRenderer); if (mitk::LookupTable::LookupTableType::MULTILABEL == lookupTable->GetActiveType()) { // special case: multilabel => set the level window to include the whole pixel range UseWholePixelRange(dataNode); } - mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(dataNode->GetProperty("Image Rendering.Mode")); + mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(dataNode->GetProperty("Image Rendering.Mode", baseRenderer)); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } } void QmitkDataNodeColorMapAction::UseWholePixelRange(mitk::DataNode* node) { auto image = dynamic_cast(node->GetData()); if (nullptr != image) { mitk::LevelWindow levelWindow; levelWindow.SetToImageRange(image); node->SetLevelWindow(levelWindow); } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.h index 659bd92ef8..6e061c5b7a 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeColorMapAction.h @@ -1,53 +1,52 @@ /*=================================================================== 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 QMITKDATANODECOLORMAPACTION_H #define QMITKDATANODECOLORMAPACTION_H #include #include "QmitkAbstractDataNodeAction.h" // mitk core #include // qt #include class MITK_QT_APP QmitkDataNodeColorMapAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeColorMapAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeColorMapAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeColorMapAction() override; - private Q_SLOTS: void OnMenuAboutShow(); void OnActionTriggered(bool); protected: virtual void InitializeAction() override; void UseWholePixelRange(mitk::DataNode* node); + }; #endif // QMITKDATANODECOLORMAPACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.cpp index 8e6a9a4468..18585a37bf 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.cpp @@ -1,108 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // mitk core #include #include #include // mitk gui common plugin #include // qt #include #include QmitkDataNodeComponentAction::QmitkDataNodeComponentAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QWidgetAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { InitializeAction(); } QmitkDataNodeComponentAction::QmitkDataNodeComponentAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QWidgetAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { InitializeAction(); } -QmitkDataNodeComponentAction::~QmitkDataNodeComponentAction() -{ - // nothing here -} - void QmitkDataNodeComponentAction::InitializeAction() { setCheckable(true); m_ComponentSlider = new QmitkNumberPropertySlider; m_ComponentSlider->setOrientation(Qt::Horizontal); QLabel* componentLabel = new QLabel(tr("Component: ")); QHBoxLayout* componentWidgetLayout = new QHBoxLayout; componentWidgetLayout->setContentsMargins(4, 4, 4, 4); componentWidgetLayout->addWidget(componentLabel); componentWidgetLayout->addWidget(m_ComponentSlider); QLabel* componentValueLabel = new QLabel(); componentWidgetLayout->addWidget(componentValueLabel); connect(m_ComponentSlider, &QmitkNumberPropertySlider::valueChanged, componentValueLabel, static_cast(&QLabel::setNum)); QWidget* componentWidget = new QWidget; componentWidget->setLayout(componentWidgetLayout); setDefaultWidget(componentWidget); connect(this, &QmitkDataNodeComponentAction::changed, this, &QmitkDataNodeComponentAction::OnActionChanged); } void QmitkDataNodeComponentAction::InitializeWithDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { m_ComponentSlider->SetProperty(static_cast(nullptr)); return; } mitk::Image* img = dynamic_cast(dataNode->GetData()); if (nullptr == img) { m_ComponentSlider->SetProperty(static_cast(nullptr)); return; } + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + int numComponents = 0; numComponents = img->GetPixelType().GetNumberOfComponents(); - mitk::IntProperty* componentProperty = dynamic_cast(dataNode->GetProperty("Image.Displayed Component")); + mitk::IntProperty* componentProperty = dynamic_cast(dataNode->GetProperty("Image.Displayed Component", baseRenderer)); if (numComponents <= 1 || nullptr == componentProperty) { m_ComponentSlider->SetProperty(static_cast(nullptr)); return; } m_ComponentSlider->SetProperty(componentProperty); m_ComponentSlider->setMinValue(0); m_ComponentSlider->setMaxValue(numComponents - 1); } void QmitkDataNodeComponentAction::OnActionChanged() { auto dataNode = GetSelectedNode(); InitializeWithDataNode(dataNode); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.h index 3da6b93db6..461611044d 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeComponentAction.h @@ -1,57 +1,55 @@ /*=================================================================== 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 QMITKDATANODECOMPONENTACTION_H #define QMITKDATANODECOMPONENTACTION_H #include // qt widgets ext module #include #include "QmitkAbstractDataNodeAction.h" // qt #include class MITK_QT_APP QmitkDataNodeComponentAction : public QWidgetAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeComponentAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeComponentAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeComponentAction() override; - virtual void InitializeWithDataNode(const mitk::DataNode* dataNode) override; private Q_SLOTS: void OnActionChanged(); protected: virtual void InitializeAction() override; private: QmitkNumberPropertySlider* m_ComponentSlider; }; #endif // QMITKDATANODECOMPONENTACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp index 4c4f38063a..30ba7e157f 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.cpp @@ -1,540 +1,556 @@ /*=================================================================== 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 "QmitkDataNodeContextMenu.h" // mitk gui qt application plugin #include "mitkIContextMenuAction.h" #include "QmitkFileSaveAction.h" // mitk gui common plugin #include // qt widgets module #include #include // berry #include #include #include #include #include QmitkDataNodeContextMenu::QmitkDataNodeContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent) : QMenu(parent) { m_Parent = parent; m_WorkbenchPartSite = workbenchPartSite; InitNodeDescriptors(); InitDefaultActions(); InitExtensionPointActions(); } QmitkDataNodeContextMenu::~QmitkDataNodeContextMenu() { // remove the registered actions from each descriptor for (DescriptorActionListType::const_iterator it = m_DescriptorActionList.begin(); it != m_DescriptorActionList.end(); ++it) { (it->first)->RemoveAction(it->second); } } void QmitkDataNodeContextMenu::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage - also for all actions m_DataStorage = dataStorage; for (DescriptorActionListType::const_iterator it = m_DescriptorActionList.begin(); it != m_DescriptorActionList.end(); ++it) { QmitkAbstractDataNodeAction* abstractDataNodeAction = dynamic_cast(it->second); if(nullptr != abstractDataNodeAction) { abstractDataNodeAction->SetDataStorage(m_DataStorage.Lock()); } } } } +void QmitkDataNodeContextMenu::SetBaseRenderer(mitk::BaseRenderer* baseRenderer) +{ + if (m_BaseRenderer != baseRenderer) + { + // set the new base renderer - also for all actions + m_BaseRenderer = baseRenderer; + for (DescriptorActionListType::const_iterator it = m_DescriptorActionList.begin(); it != m_DescriptorActionList.end(); ++it) + { + QmitkAbstractDataNodeAction *abstractDataNodeAction = dynamic_cast(it->second); + if (nullptr != abstractDataNodeAction) + { + abstractDataNodeAction->SetBaseRenderer(m_BaseRenderer.Lock()); + } + } + } +} + void QmitkDataNodeContextMenu::SetSurfaceDecimation(bool surfaceDecimation) { m_SurfaceDecimation = surfaceDecimation; } void QmitkDataNodeContextMenu::SetSelectedNodes(const QList& selectedNodes) { m_SelectedNodes = selectedNodes; } void QmitkDataNodeContextMenu::InitNodeDescriptors() { m_UnknownDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetUnknownDataNodeDescriptor(); m_ImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Image"); m_MultiComponentImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("MultiComponentImage"); m_DiffusionImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("DiffusionImage"); m_FiberBundleDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("FiberBundle"); m_PeakImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PeakImage"); m_SegmentDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Segment"); m_SurfaceDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Surface"); m_PointSetNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PointSet"); m_PlanarLineNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarLine"); m_PlanarCircleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarCircle"); m_PlanarEllipseNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarEllipse"); m_PlanarAngleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarAngle"); m_PlanarFourPointAngleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarFourPointAngle"); m_PlanarRectangleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarRectangle"); m_PlanarPolygonNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarPolygon"); m_PlanarPathNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarPath"); m_PlanarDoubleEllipseNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarDoubleEllipse"); m_PlanarBezierCurveNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarBezierCurve"); m_PlanarSubdivisionPolygonNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarSubdivisionPolygon"); } void QmitkDataNodeContextMenu::InitDefaultActions() { m_GlobalReinitAction = new QmitkDataNodeGlobalReinitAction(m_Parent, m_WorkbenchPartSite.Lock()); m_GlobalReinitAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_GlobalReinitAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_GlobalReinitAction)); m_ReinitAction = new QmitkDataNodeReinitAction(m_Parent, m_WorkbenchPartSite.Lock()); m_ReinitAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ReinitAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ReinitAction)); QAction* saveAction = new QmitkFileSaveAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), m_WorkbenchPartSite.Lock()->GetWorkbenchWindow()); m_UnknownDataNodeDescriptor->AddAction(saveAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, saveAction)); m_RemoveAction = new QmitkDataNodeRemoveAction(m_Parent, m_WorkbenchPartSite.Lock()); m_RemoveAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/Remove_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_RemoveAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_RemoveAction)); m_ShowSelectedNodesAction = new QmitkDataNodeShowSelectedNodesAction(m_Parent, m_WorkbenchPartSite.Lock()); m_RemoveAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/ShowSelectedNode_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ShowSelectedNodesAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ShowSelectedNodesAction)); m_ToggleVisibilityAction = new QmitkDataNodeToggleVisibilityAction(m_Parent, m_WorkbenchPartSite.Lock()); m_ToggleVisibilityAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/InvertShowSelectedNode_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ToggleVisibilityAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ToggleVisibilityAction)); m_ShowDetailsAction = new QmitkDataNodeShowDetailsAction(m_Parent, m_WorkbenchPartSite.Lock()); m_ShowDetailsAction->setIcon(QIcon(":/org.mitk.gui.qt.datamanager/ShowDataInfo_48.png")); m_UnknownDataNodeDescriptor->AddAction(m_ShowDetailsAction, true); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_ShowDetailsAction)); // default widget actions m_OpacityAction = new QmitkDataNodeOpacityAction(m_Parent, m_WorkbenchPartSite.Lock()); // not used for batch actions (no multi-selection action) m_UnknownDataNodeDescriptor->AddAction(m_OpacityAction, false); m_DescriptorActionList.push_back(std::make_pair(m_UnknownDataNodeDescriptor, m_OpacityAction)); m_ColorAction = new QmitkDataNodeColorAction(m_Parent, m_WorkbenchPartSite.Lock()); AddColorAction(m_ColorAction); m_ColormapAction = new QmitkDataNodeColorMapAction(m_Parent, m_WorkbenchPartSite.Lock()); // used for batch actions m_ImageDataNodeDescriptor->AddAction(m_ColormapAction); m_DescriptorActionList.push_back(std::make_pair(m_ImageDataNodeDescriptor, m_ColormapAction)); if (m_DiffusionImageDataNodeDescriptor != nullptr) { // not used for batch actions (no multi-selection action) m_DiffusionImageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, m_ColormapAction)); } m_ComponentAction = new QmitkDataNodeComponentAction(m_Parent, m_WorkbenchPartSite.Lock()); // not used for batch actions (no multi-selection action) m_MultiComponentImageDataNodeDescriptor->AddAction(m_ComponentAction, false); m_DescriptorActionList.push_back(std::make_pair(m_MultiComponentImageDataNodeDescriptor, m_ComponentAction)); if (m_DiffusionImageDataNodeDescriptor != nullptr) { // not used for batch actions (no multi-selection action) m_DiffusionImageDataNodeDescriptor->AddAction(m_ComponentAction, false); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, m_ComponentAction)); } m_TextureInterpolationAction = new QmitkDataNodeTextureInterpolationAction(m_Parent, m_WorkbenchPartSite.Lock()); // not used for batch actions (no multi-selection action) m_ImageDataNodeDescriptor->AddAction(m_TextureInterpolationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_ImageDataNodeDescriptor, m_TextureInterpolationAction)); if (m_DiffusionImageDataNodeDescriptor != nullptr) { // not used for batch actions (no multi-selection action) m_DiffusionImageDataNodeDescriptor->AddAction(m_TextureInterpolationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, m_TextureInterpolationAction)); } if (m_SegmentDataNodeDescriptor != nullptr) { // not used for batch actions (no multi-selection action) m_SegmentDataNodeDescriptor->AddAction(m_TextureInterpolationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_SegmentDataNodeDescriptor, m_TextureInterpolationAction)); } m_SurfaceRepresentationAction = new QmitkDataNodeSurfaceRepresentationAction(m_Parent, m_WorkbenchPartSite.Lock()); // not used for batch actions (no multi-selection action) m_SurfaceDataNodeDescriptor->AddAction(m_SurfaceRepresentationAction, false); m_DescriptorActionList.push_back(std::make_pair(m_SurfaceDataNodeDescriptor, m_SurfaceRepresentationAction)); } void QmitkDataNodeContextMenu::InitExtensionPointActions() { // find contextMenuAction extension points and add them to the node descriptor berry::IExtensionRegistry* extensionPointService = berry::Platform::GetExtensionRegistry(); QList customMenuConfigs = extensionPointService->GetConfigurationElementsFor("org.mitk.gui.qt.datamanager.contextMenuActions"); // prepare all custom QActions m_ConfigElements.clear(); DescriptorActionListType descriptorActionList; for (const auto& customMenuConfig : customMenuConfigs) { QString actionNodeDescriptorName = customMenuConfig->GetAttribute("nodeDescriptorName"); QString actionLabel = customMenuConfig->GetAttribute("label"); QString actionClass = customMenuConfig->GetAttribute("class"); if (actionNodeDescriptorName.isEmpty() || actionLabel.isEmpty() || actionClass.isEmpty()) { // no properties found for the current extension point continue; } // find matching descriptor auto nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(actionNodeDescriptorName); if (nullptr == nodeDescriptor) { MITK_WARN << "Cannot add action \"" << actionLabel << "\" because descriptor " << actionNodeDescriptorName << " does not exist."; continue; } // create action with or without icon QAction* contextMenuAction; QString actionIconName = customMenuConfig->GetAttribute("icon"); if (!actionIconName.isEmpty()) { QIcon actionIcon; if (QFile::exists(actionIconName)) { actionIcon = QIcon(actionIconName); } else { actionIcon = berry::AbstractUICTKPlugin::ImageDescriptorFromPlugin(customMenuConfig->GetContributor()->GetName(), actionIconName); } contextMenuAction = new QAction(actionIcon, actionLabel, m_Parent); } else { contextMenuAction = new QAction(actionLabel, m_Parent); } // connect action trigger connect(contextMenuAction, static_cast(&QAction::triggered), this, &QmitkDataNodeContextMenu::OnExtensionPointActionTriggered); // mark configuration element into lookup list for context menu handler m_ConfigElements[contextMenuAction] = customMenuConfig; // mark new action in sortable list for addition to descriptor descriptorActionList.emplace_back(nodeDescriptor, contextMenuAction); } AddDescriptorActionList(descriptorActionList); } void QmitkDataNodeContextMenu::InitServiceActions() { - } void QmitkDataNodeContextMenu::OnContextMenuRequested(const QPoint& /*pos*/) { if (m_WorkbenchPartSite.Expired()) { return; } if (m_SelectedNodes.isEmpty()) { // no selection set - retrieve selection from the workbench selection service m_SelectedNodes = AbstractDataNodeAction::GetSelectedNodes(m_WorkbenchPartSite.Lock()); } // if either a selection was set or a selection could be retrieved from the workbench selection service + berry::ISelection::ConstPointer selection = m_WorkbenchPartSite.Lock()->GetWorkbenchWindow()->GetSelectionService()->GetSelection(); + mitk::DataNodeSelection::ConstPointer currentSelection = selection.Cast(); + + if (currentSelection.IsNull() || currentSelection->IsEmpty()) + { + return; + } + + m_SelectedNodes = QList::fromStdList(currentSelection->GetSelectedDataNodes()); if (!m_SelectedNodes.isEmpty()) { clear(); QList actions; if (m_SelectedNodes.size() == 1) { // no batch action; should only contain a single node actions = GetActions(m_SelectedNodes.front()); } else { // batch action actions = GetActions(m_SelectedNodes); } // initialize abstract data node actions for (auto& action : actions) { QmitkAbstractDataNodeAction* abstractDataNodeAction = dynamic_cast(action); if (nullptr != abstractDataNodeAction) { abstractDataNodeAction->SetSelectedNodes(m_SelectedNodes); } } - - /* - if (!m_ShowInActions.isEmpty()) - { - QMenu* showInMenu = m_NodeMenu->addMenu(tr("Show In")); - showInMenu->addActions(m_ShowInActions); - } - */ - addActions(actions); popup(QCursor::pos()); } } void QmitkDataNodeContextMenu::OnExtensionPointActionTriggered(bool) { QAction* action = qobject_cast(sender()); ConfigurationElementsType::const_iterator it = m_ConfigElements.find(action); if (it == m_ConfigElements.end()) { MITK_WARN << "Associated configuration element for action " << action->text().toStdString() << " not found."; return; } berry::IConfigurationElement::Pointer confElem = it->second; mitk::IContextMenuAction* contextMenuAction = confElem->CreateExecutableExtension("class"); QString className = confElem->GetAttribute("class"); QString smoothed = confElem->GetAttribute("smoothed"); if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); contextMenuAction->SetDataStorage(dataStorage); } if (className == "QmitkCreatePolygonModelAction") { if (smoothed == "false") { contextMenuAction->SetSmoothed(false); } else { contextMenuAction->SetSmoothed(true); } contextMenuAction->SetDecimated(m_SurfaceDecimation); } contextMenuAction->Run(m_SelectedNodes); } void QmitkDataNodeContextMenu::AddColorAction(QWidgetAction* colorAction) { bool colorActionCanBatch = true; if (nullptr != m_ImageDataNodeDescriptor) { m_ImageDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_ImageDataNodeDescriptor, colorAction)); } if (nullptr != m_MultiComponentImageDataNodeDescriptor) { m_MultiComponentImageDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_MultiComponentImageDataNodeDescriptor, colorAction)); } if (nullptr != m_DiffusionImageDataNodeDescriptor) { m_DiffusionImageDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_DiffusionImageDataNodeDescriptor, colorAction)); } if (nullptr != m_FiberBundleDataNodeDescriptor) { m_FiberBundleDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::make_pair(m_FiberBundleDataNodeDescriptor, colorAction)); } if (nullptr != m_PeakImageDataNodeDescriptor) { m_PeakImageDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::make_pair(m_PeakImageDataNodeDescriptor, colorAction)); } if (nullptr != m_SegmentDataNodeDescriptor) { m_SegmentDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::make_pair(m_SegmentDataNodeDescriptor, colorAction)); } if (nullptr != m_SurfaceDataNodeDescriptor) { m_SurfaceDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_SurfaceDataNodeDescriptor, colorAction)); } if (nullptr != m_PointSetNodeDescriptor) { m_PointSetNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PointSetNodeDescriptor, colorAction)); } if (nullptr != m_PlanarLineNodeDescriptor) { m_PlanarLineNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarLineNodeDescriptor, colorAction)); } if (nullptr != m_PlanarCircleNodeDescriptor) { m_PlanarCircleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarCircleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarEllipseNodeDescriptor) { m_PlanarEllipseNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarEllipseNodeDescriptor, colorAction)); } if (nullptr != m_PlanarAngleNodeDescriptor) { m_PlanarAngleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarAngleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarFourPointAngleNodeDescriptor) { m_PlanarFourPointAngleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarFourPointAngleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarRectangleNodeDescriptor) { m_PlanarRectangleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarRectangleNodeDescriptor, colorAction)); } if (nullptr != m_PlanarPolygonNodeDescriptor) { m_PlanarPolygonNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarPolygonNodeDescriptor, colorAction)); } if (nullptr != m_PlanarPathNodeDescriptor) { m_PlanarPathNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarPathNodeDescriptor, colorAction)); } if (nullptr != m_PlanarDoubleEllipseNodeDescriptor) { m_PlanarDoubleEllipseNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarDoubleEllipseNodeDescriptor, colorAction)); } if (nullptr != m_PlanarBezierCurveNodeDescriptor) { m_PlanarBezierCurveNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarBezierCurveNodeDescriptor, colorAction)); } if (nullptr != m_PlanarSubdivisionPolygonNodeDescriptor) { m_PlanarSubdivisionPolygonNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back(std::make_pair(m_PlanarSubdivisionPolygonNodeDescriptor, colorAction)); } } void QmitkDataNodeContextMenu::AddDescriptorActionList(DescriptorActionListType& descriptorActionList) { // sort all custom QActions by their texts using ListEntryType = std::pair; std::sort(descriptorActionList.begin(), descriptorActionList.end(), [](const ListEntryType& left, const ListEntryType& right) -> bool { assert(left.second != nullptr && right.second != nullptr); // unless we messed up above return left.second->text() < right.second->text(); }); // add custom QActions in sorted order for (auto& descriptorActionPair : descriptorActionList) { auto& nodeDescriptor = descriptorActionPair.first; auto& contextMenuAction = descriptorActionPair.second; // add action to the descriptor nodeDescriptor->AddAction(contextMenuAction); // mark new action into list of descriptors to remove in destructor m_DescriptorActionList.push_back(descriptorActionPair); } } QList QmitkDataNodeContextMenu::GetActions(const mitk::DataNode* node) { QList actions; for (DescriptorActionListType::const_iterator it = m_DescriptorActionList.begin(); it != m_DescriptorActionList.end(); ++it) { if ((it->first)->CheckNode(node) || it->first->GetNameOfClass() == "Unknown") { actions.append(it->second); } } return actions; } QList QmitkDataNodeContextMenu::GetActions(const QList& nodes) { QList actions; for (DescriptorActionListType::const_iterator it = m_DescriptorActionList.begin(); it != m_DescriptorActionList.end(); ++it) { for (const auto& node : nodes) { if ((it->first)->CheckNode(node) || it->first->GetNameOfClass() == "Unknown") { const auto& batchActions = (it->first)->GetBatchActions(); if (std::find(batchActions.begin(), batchActions.end(), it->second) != batchActions.end()) { // current descriptor action is a batch action actions.append(it->second); } break; // only add action once; goto next descriptor action } } } return actions; } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.h index 28a747698e..723c8d7529 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeContextMenu.h @@ -1,136 +1,140 @@ /*=================================================================== 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 QMITKDATANODECONTEXTMENU_H #define QMITKDATANODECONTEXTMENU_H #include // qt widgets module #include "QmitkDataNodeGlobalReinitAction.h" #include "QmitkDataNodeReinitAction.h" #include "QmitkDataNodeRemoveAction.h" #include "QmitkDataNodeShowSelectedNodesAction.h" #include "QmitkDataNodeToggleVisibilityAction.h" #include "QmitkDataNodeShowDetailsAction.h" #include "QmitkDataNodeOpacityAction.h" #include "QmitkDataNodeColorAction.h" #include "QmitkDataNodeColorMapAction.h" #include "QmitkDataNodeComponentAction.h" #include "QmitkDataNodeTextureInterpolationAction.h" #include "QmitkDataNodeSurfaceRepresentationAction.h" #include "QmitkNodeDescriptor.h" // mitk core +#include #include #include // blueberry ui qt plugin #include #include // qt #include class MITK_QT_APP QmitkDataNodeContextMenu : public QMenu { Q_OBJECT public: QmitkDataNodeContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent = nullptr); virtual ~QmitkDataNodeContextMenu() override; void SetDataStorage(mitk::DataStorage* dataStorage); + void SetBaseRenderer(mitk::BaseRenderer* baseRenderer); + void SetSurfaceDecimation(bool surfaceDecimation); void SetSelectedNodes(const QList& selectedNodes); public Q_SLOTS: void OnContextMenuRequested(const QPoint& pos); void OnExtensionPointActionTriggered(bool); private: using DescriptorActionListType = std::vector>; using ConfigurationElementsType = std::map; void InitNodeDescriptors(); void InitDefaultActions(); void InitExtensionPointActions(); void InitServiceActions(); void AddColorAction(QWidgetAction* colorAction); void AddDescriptorActionList(DescriptorActionListType& descriptorActionList); QList GetActions(const mitk::DataNode* node); - QList GetActions(const QList& selectedNodes); + QList GetActions(const QList& nodes); QWidget* m_Parent; berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite; mitk::WeakPointer m_DataStorage; + mitk::WeakPointer m_BaseRenderer; QList m_SelectedNodes; // store a list of all actions to remove them on menu destruction DescriptorActionListType m_DescriptorActionList; // stores the configuration elements for the context menu actions from extension points ConfigurationElementsType m_ConfigElements; QmitkNodeDescriptor* m_UnknownDataNodeDescriptor; QmitkNodeDescriptor* m_ImageDataNodeDescriptor; QmitkNodeDescriptor* m_MultiComponentImageDataNodeDescriptor; QmitkNodeDescriptor* m_DiffusionImageDataNodeDescriptor; QmitkNodeDescriptor* m_FiberBundleDataNodeDescriptor; QmitkNodeDescriptor* m_PeakImageDataNodeDescriptor; QmitkNodeDescriptor* m_SegmentDataNodeDescriptor; QmitkNodeDescriptor* m_SurfaceDataNodeDescriptor; QmitkNodeDescriptor* m_PointSetNodeDescriptor; QmitkNodeDescriptor* m_PlanarLineNodeDescriptor; QmitkNodeDescriptor* m_PlanarCircleNodeDescriptor; QmitkNodeDescriptor* m_PlanarEllipseNodeDescriptor; QmitkNodeDescriptor* m_PlanarAngleNodeDescriptor; QmitkNodeDescriptor* m_PlanarFourPointAngleNodeDescriptor; QmitkNodeDescriptor* m_PlanarRectangleNodeDescriptor; QmitkNodeDescriptor* m_PlanarPolygonNodeDescriptor; QmitkNodeDescriptor* m_PlanarPathNodeDescriptor; QmitkNodeDescriptor* m_PlanarDoubleEllipseNodeDescriptor; QmitkNodeDescriptor* m_PlanarBezierCurveNodeDescriptor; QmitkNodeDescriptor* m_PlanarSubdivisionPolygonNodeDescriptor; ////////////////////////////////////////////////////////////////////////// // default actions ////////////////////////////////////////////////////////////////////////// QmitkDataNodeGlobalReinitAction* m_GlobalReinitAction; QmitkDataNodeReinitAction* m_ReinitAction; QmitkDataNodeRemoveAction* m_RemoveAction; QmitkDataNodeShowSelectedNodesAction* m_ShowSelectedNodesAction; QmitkDataNodeToggleVisibilityAction* m_ToggleVisibilityAction; QmitkDataNodeShowDetailsAction* m_ShowDetailsAction; QmitkDataNodeOpacityAction* m_OpacityAction; QmitkDataNodeColorAction* m_ColorAction; QmitkDataNodeColorMapAction* m_ColormapAction; QmitkDataNodeComponentAction* m_ComponentAction; QmitkDataNodeTextureInterpolationAction* m_TextureInterpolationAction; QmitkDataNodeSurfaceRepresentationAction* m_SurfaceRepresentationAction; bool m_SurfaceDecimation; }; #endif // QMITKDATANODECONTEXTMENU_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp index b38a0fe561..67a41d937a 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp @@ -1,86 +1,81 @@ /*=================================================================== 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 gui common plugin #include const QString QmitkDataNodeGlobalReinitAction::ACTION_ID = "org.mitk.gui.qt.application.globalreinitaction"; // namespace that contains the concrete action namespace GlobalReinitAction { void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage) { auto renderWindow = mitk::WorkbenchUtil::GetRenderWindowPart(workbenchPartSite->GetPage(), mitk::WorkbenchUtil::NONE); if (nullptr == renderWindow) { renderWindow = mitk::WorkbenchUtil::OpenRenderWindowPart(workbenchPartSite->GetPage(), false); if (nullptr == renderWindow) { // no render window available return; } } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); } } QmitkDataNodeGlobalReinitAction::QmitkDataNodeGlobalReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchPartSite) { setText(tr("Global Reinit")); InitializeAction(); } QmitkDataNodeGlobalReinitAction::QmitkDataNodeGlobalReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Global Reinit")); InitializeAction(); } -QmitkDataNodeGlobalReinitAction::~QmitkDataNodeGlobalReinitAction() -{ - // nothing here -} - void QmitkDataNodeGlobalReinitAction::InitializeAction() { connect(this, &QmitkDataNodeGlobalReinitAction::triggered, this, &QmitkDataNodeGlobalReinitAction::OnActionTriggered); } void QmitkDataNodeGlobalReinitAction::OnActionTriggered(bool /*checked*/) { if (m_WorkbenchPartSite.Expired()) { return; } if (m_DataStorage.IsExpired()) { return; } GlobalReinitAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock()); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.h index 5202843495..8c1a9f1a69 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.h @@ -1,55 +1,53 @@ /*=================================================================== 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 QMITKDATANODEGLOBALREINITACTION_H #define QMITKDATANODEGLOBALREINITACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include namespace GlobalReinitAction { MITK_QT_APP void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage); } class MITK_QT_APP QmitkDataNodeGlobalReinitAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: static const QString ACTION_ID; // = "org.mitk.gui.qt.application.globalreinitaction"; QmitkDataNodeGlobalReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeGlobalReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeGlobalReinitAction() override; - private Q_SLOTS: void OnActionTriggered(bool); private: virtual void InitializeAction() override; }; #endif // QMITKDATANODEGLOBALREINITACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp index 6fd79b3018..3d1649525b 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp @@ -1,73 +1,77 @@ /*=================================================================== 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 namespace HideAllAction { - void Run(QList selectedNodes) + void Run(const QList& selectedNodes, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { if (selectedNodes.empty()) { return; } for (auto& node : selectedNodes) { if (node.IsNotNull()) { - node->SetVisibility(false); + node->SetVisibility(false, baseRenderer); } } - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } } QmitkDataNodeHideAllAction::QmitkDataNodeHideAllAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Hide all nodes")); InitializeAction(); } QmitkDataNodeHideAllAction::QmitkDataNodeHideAllAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Hide all nodes")); InitializeAction(); } -QmitkDataNodeHideAllAction::~QmitkDataNodeHideAllAction() -{ - // nothing here -} - void QmitkDataNodeHideAllAction::InitializeAction() { connect(this, &QmitkDataNodeHideAllAction::triggered, this, &QmitkDataNodeHideAllAction::OnActionTriggered); } void QmitkDataNodeHideAllAction::OnActionTriggered(bool /*checked*/) { + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + auto selectedNodes = GetSelectedNodes(); - HideAllAction::Run(selectedNodes); + HideAllAction::Run(selectedNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.h index 3bc4a09792..3f5435a221 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.h @@ -1,53 +1,52 @@ /*=================================================================== 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 QMITKDATANODEHIDEALLACTION_H #define QMITKDATANODEHIDEALLACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include namespace HideAllAction { - MITK_QT_APP void Run(QList selectedNodes); + MITK_QT_APP void Run(const QList& selectedNodes, + mitk::BaseRenderer* baseRenderer = nullptr); } class MITK_QT_APP QmitkDataNodeHideAllAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeHideAllAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeHideAllAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeHideAllAction() override; - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; }; #endif // QMITKDATANODEHIDEALLACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.cpp index 58c58830bc..94f8d317f6 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.cpp @@ -1,99 +1,111 @@ /*=================================================================== 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 // qt #include #include QmitkDataNodeOpacityAction::QmitkDataNodeOpacityAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QWidgetAction(parent) , QmitkAbstractDataNodeAction(workbenchPartSite) { InitializeAction(); } QmitkDataNodeOpacityAction::QmitkDataNodeOpacityAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QWidgetAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { InitializeAction(); } -QmitkDataNodeOpacityAction::~QmitkDataNodeOpacityAction() -{ - // nothing here -} - void QmitkDataNodeOpacityAction::InitializeAction() { m_OpacitySlider = new QSlider; m_OpacitySlider->setMinimum(0); m_OpacitySlider->setMaximum(100); m_OpacitySlider->setOrientation(Qt::Horizontal); connect(m_OpacitySlider, &QSlider::valueChanged, this, &QmitkDataNodeOpacityAction::OnOpacityChanged); QLabel* opacityLabel = new QLabel(tr("Opacity: ")); QHBoxLayout* opacityWidgetLayout = new QHBoxLayout; opacityWidgetLayout->setContentsMargins(4, 4, 4, 4); opacityWidgetLayout->addWidget(opacityLabel); opacityWidgetLayout->addWidget(m_OpacitySlider); QWidget* opacityWidget = new QWidget; opacityWidget->setLayout(opacityWidgetLayout); setDefaultWidget(opacityWidget); connect(this, &QAction::changed, this, &QmitkDataNodeOpacityAction::OnActionChanged); } void QmitkDataNodeOpacityAction::InitializeWithDataNode(const mitk::DataNode* dataNode) { + if (nullptr == dataNode) + { + m_OpacitySlider->setValue(static_cast(0)); + return; + } + + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + float opacity = 0.0; - if (dataNode->GetFloatProperty("opacity", opacity)) + if (dataNode->GetFloatProperty("opacity", opacity, baseRenderer)) { m_OpacitySlider->setValue(static_cast(opacity * 100)); } } void QmitkDataNodeOpacityAction::OnOpacityChanged(int value) { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + float opacity = static_cast(value) / 100.0f; - dataNode->SetFloatProperty("opacity", opacity); + dataNode->SetFloatProperty("opacity", opacity, baseRenderer); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } void QmitkDataNodeOpacityAction::OnActionChanged() { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } InitializeWithDataNode(dataNode); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.h index 11889808ab..e1ed60d612 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpacityAction.h @@ -1,54 +1,52 @@ /*=================================================================== 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 QMITKDATANODEOPACITYACTION_H #define QMITKDATANODEOPACITYACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include #include class MITK_QT_APP QmitkDataNodeOpacityAction : public QWidgetAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeOpacityAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeOpacityAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeOpacityAction() override; - virtual void InitializeWithDataNode(const mitk::DataNode* dataNode) override; private Q_SLOTS: void OnOpacityChanged(int); void OnActionChanged(); protected: virtual void InitializeAction() override; QSlider* m_OpacitySlider; }; #endif // QMITKDATANODEOPACITYACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpenInAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpenInAction.h index 5d18b76ddd..403cafc12a 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpenInAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeOpenInAction.h @@ -1,60 +1,60 @@ /*=================================================================== 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 QMITKDATANODEOPENINACTION_H #define QMITKDATANODEOPENINACTION_H #include #include "QmitkAbstractDataNodeAction.h" // mitk core #include // qt #include class MITK_QT_APP QmitkDataNodeOpenInAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: - typedef std::vector RendererVector; + typedef std::vector RendererVector; QmitkDataNodeOpenInAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeOpenInAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); virtual ~QmitkDataNodeOpenInAction() override; void SetControlledRenderer(RendererVector controlledRenderer); private Q_SLOTS: void OnMenuAboutToShow(); void OnActionTriggered(bool); protected: virtual void InitializeAction() override; void SetControlledRenderer(); RendererVector m_ControlledRenderer; }; #endif // QMITKDATANODEOPENINACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp index a3f8d6b126..9b52293f3e 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp @@ -1,123 +1,134 @@ /*=================================================================== 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 #include #include #include #include // mitk gui common plugin #include // namespace that contains the concrete action namespace ReinitAction { - void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, QList selectedNodes) + void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, const QList& selectedNodes /*= QList()*/, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { if (selectedNodes.empty()) { return; } auto renderWindow = mitk::WorkbenchUtil::GetRenderWindowPart(workbenchPartSite->GetPage(), mitk::WorkbenchUtil::NONE); if (nullptr == renderWindow) { renderWindow = mitk::WorkbenchUtil::OpenRenderWindowPart(workbenchPartSite->GetPage(), false); if (nullptr == renderWindow) { // no render window available return; } } - auto boundingBoxPredicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); + auto boundingBoxPredicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false), baseRenderer)); mitk::DataStorage::SetOfObjects::Pointer nodes = mitk::DataStorage::SetOfObjects::New(); for (const auto& dataNode : selectedNodes) { if (boundingBoxPredicate->CheckNode(dataNode)) { nodes->InsertElement(nodes->Size(), dataNode); } } if (nodes->empty()) { return; } if (1 == nodes->Size()) // Special case: If exactly one ... { - auto image = dynamic_cast(nodes->ElementAt(0)->GetData()); + auto image = dynamic_cast(nodes->ElementAt(0)->GetData()); if (nullptr != image) // ... image is selected, reinit is expected to rectify askew images. { - mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + } + else + { + mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), image->GetTimeGeometry(), true); + } return; } } - auto boundingGeometry = dataStorage->ComputeBoundingGeometry3D(nodes, "visible"); - mitk::RenderingManager::GetInstance()->InitializeViews(boundingGeometry); + auto boundingGeometry = dataStorage->ComputeBoundingGeometry3D(nodes, "visible", baseRenderer); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->InitializeViews(boundingGeometry); + } + else + { + mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), boundingGeometry); + } } } QmitkDataNodeReinitAction::QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Reinit")); InitializeAction(); } QmitkDataNodeReinitAction::QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Reinit")); InitializeAction(); } -QmitkDataNodeReinitAction::~QmitkDataNodeReinitAction() -{ - // nothing here -} - void QmitkDataNodeReinitAction::InitializeAction() { connect(this, &QmitkDataNodeReinitAction::triggered, this, &QmitkDataNodeReinitAction::OnActionTriggered); } void QmitkDataNodeReinitAction::OnActionTriggered(bool /*checked*/) { if (m_WorkbenchPartSite.Expired()) { return; } if (m_DataStorage.IsExpired()) { return; } + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + auto selectedNodes = GetSelectedNodes(); - ReinitAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock(), selectedNodes); + ReinitAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock(), selectedNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.h index 41b5b16731..f93b1b89ca 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.h @@ -1,55 +1,54 @@ /*=================================================================== 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 QMITKDATANODEREINITACTION_H #define QMITKDATANODEREINITACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include namespace ReinitAction { MITK_QT_APP void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, - QList selectedNodes); + const QList& selectedNodes = QList(), + mitk::BaseRenderer* baseRenderer = nullptr); } class MITK_QT_APP QmitkDataNodeReinitAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeReinitAction() override; - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; }; #endif // QMITKDATANODEREINITACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.cpp index 3232361e22..545d48daab 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.cpp @@ -1,123 +1,118 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include // qt #include // berry #include #include #include namespace RemoveAction { - void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, QList selectedNodes, QWidget* parent /* = nullptr*/) + void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, const QList& selectedNodes, QWidget* parent /* = nullptr*/) { if (selectedNodes.empty()) { return; } QString question("Do you really want to remove "); for (auto& dataNode : selectedNodes) { if (nullptr == dataNode) { continue; } question.append(QString::fromStdString(dataNode->GetName())); question.append(", "); } // remove the last two characters = ", " question = question.remove(question.size() - 2, 2); question.append(" from data storage?"); QMessageBox::StandardButton answerButton = QMessageBox::question(parent, "DataManager", question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { for (auto& dataNode : selectedNodes) { if (nullptr == dataNode) { continue; } dataStorage->Remove(dataNode); } berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IPreferences::Pointer preferencesNode = prefService->GetSystemPreferences()->Node(QmitkDataNodeGlobalReinitAction::ACTION_ID); bool globalReinit = preferencesNode->GetBool("Call global reinit if node is deleted", true); if (globalReinit) { GlobalReinitAction::Run(workbenchPartSite, dataStorage); } } } } QmitkDataNodeRemoveAction::QmitkDataNodeRemoveAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Remove")); m_Parent = parent; InitializeAction(); } QmitkDataNodeRemoveAction::QmitkDataNodeRemoveAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Remove")); m_Parent = parent; InitializeAction(); } -QmitkDataNodeRemoveAction::~QmitkDataNodeRemoveAction() -{ - // nothing here -} - void QmitkDataNodeRemoveAction::InitializeAction() { connect(this, &QmitkDataNodeRemoveAction::triggered, this, &QmitkDataNodeRemoveAction::OnActionTriggered); } void QmitkDataNodeRemoveAction::OnActionTriggered(bool /*checked*/) { if (m_WorkbenchPartSite.Expired()) { return; } if (m_DataStorage.IsExpired()) { return; } auto selectedNodes = GetSelectedNodes(); RemoveAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock(), selectedNodes, m_Parent); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.h index c77ee526f6..957cb9464b 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeRemoveAction.h @@ -1,60 +1,58 @@ /*=================================================================== 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 QMITKDATANODEREMOVEACTION_H #define QMITKDATANODEREMOVEACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include namespace RemoveAction { MITK_QT_APP void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, - QList selectedNodes, + const QList& selectedNodes, QWidget* parent = nullptr); } class MITK_QT_APP QmitkDataNodeRemoveAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeRemoveAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeRemoveAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeRemoveAction() override; - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; private: QWidget* m_Parent; }; #endif // QMITKDATANODEREMOVEACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.cpp index 0c81d5b313..2430171a0e 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.cpp @@ -1,68 +1,62 @@ /*=================================================================== 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 gui qt application #include "QmitkNodeDetailsDialog.h" namespace ShowDetailsAction { - void Run(QList selectedNodes, QWidget* parent /* = nullptr*/) + void Run(const QList& selectedNodes, QWidget* parent /* = nullptr*/) { if (selectedNodes.empty()) { return; } QmitkNodeDetailsDialog infoDialog(selectedNodes, parent); infoDialog.exec(); } } QmitkDataNodeShowDetailsAction::QmitkDataNodeShowDetailsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Show details")); m_Parent = parent; InitializeAction(); } QmitkDataNodeShowDetailsAction::QmitkDataNodeShowDetailsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Show details")); m_Parent = parent; InitializeAction(); } -QmitkDataNodeShowDetailsAction::~QmitkDataNodeShowDetailsAction() -{ - // nothing here -} - void QmitkDataNodeShowDetailsAction::InitializeAction() { connect(this, &QmitkDataNodeShowDetailsAction::triggered, this, &QmitkDataNodeShowDetailsAction::OnActionTriggered); } void QmitkDataNodeShowDetailsAction::OnActionTriggered(bool /*checked*/) { auto selectedNodes = GetSelectedNodes(); ShowDetailsAction::Run(selectedNodes, m_Parent); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.h index 96b345853b..c1a64f1cfc 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowDetailsAction.h @@ -1,58 +1,56 @@ /*=================================================================== 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 QMITKDATANODESHOWDETAILSACTION_H #define QMITKDATANODESHOWDETAILSACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include namespace ShowDetailsAction { - MITK_QT_APP void Run(QList selectedNodes, + MITK_QT_APP void Run(const QList& selectedNodes, QWidget* parent = nullptr); } class MITK_QT_APP QmitkDataNodeShowDetailsAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeShowDetailsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeShowDetailsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeShowDetailsAction() override; - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; private: QWidget* m_Parent; }; #endif // QMITKDATANODESHOWDETAILSACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp index cddd229429..a2a4af5796 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp @@ -1,68 +1,70 @@ /*=================================================================== 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 QmitkDataNodeShowSelectedNodesAction::QmitkDataNodeShowSelectedNodesAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Show only selected nodes")); InitializeAction(); } QmitkDataNodeShowSelectedNodesAction::QmitkDataNodeShowSelectedNodesAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Show only selected nodes")); InitializeAction(); } -QmitkDataNodeShowSelectedNodesAction::~QmitkDataNodeShowSelectedNodesAction() -{ - // nothing here -} - void QmitkDataNodeShowSelectedNodesAction::InitializeAction() { connect(this, &QmitkDataNodeShowSelectedNodesAction::triggered, this, &QmitkDataNodeShowSelectedNodesAction::OnActionTriggered); } void QmitkDataNodeShowSelectedNodesAction::OnActionTriggered(bool /*checked*/) { if (m_DataStorage.IsExpired()) { return; } - auto dataStorage = m_DataStorage.Lock(); + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); - auto selectedNodes = GetSelectedNodes(); - auto nodeset = dataStorage->GetAll(); + auto dataNodes = GetSelectedNodes(); + auto nodeset = m_DataStorage.Lock()->GetAll(); for (auto& node : *nodeset) { if (node.IsNotNull()) { - node->SetVisibility(selectedNodes.contains(node)); + node->SetVisibility(dataNodes.contains(node), baseRenderer); } } - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.h index 1847481291..96f178407f 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.h @@ -1,48 +1,46 @@ /*=================================================================== 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 QMITKDATANODESHOWSELECTEDNODESACTION_H #define QMITKDATANODESHOWSELECTEDNODESACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include class MITK_QT_APP QmitkDataNodeShowSelectedNodesAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeShowSelectedNodesAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeShowSelectedNodesAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeShowSelectedNodesAction() override; - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; }; #endif // QMITKDATANODESHOWSELECTEDNODESACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.cpp index 88db78ae72..b4f71f7d97 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.cpp @@ -1,118 +1,122 @@ /*=================================================================== 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 #include // qt #include QmitkDataNodeSurfaceRepresentationAction::QmitkDataNodeSurfaceRepresentationAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Surface Representation")); InitializeAction(); } QmitkDataNodeSurfaceRepresentationAction::QmitkDataNodeSurfaceRepresentationAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Surface Representation")); InitializeAction(); } -QmitkDataNodeSurfaceRepresentationAction::~QmitkDataNodeSurfaceRepresentationAction() -{ - // nothing here -} - void QmitkDataNodeSurfaceRepresentationAction::InitializeAction() { setCheckable(true); setMenu(new QMenu); connect(menu(), &QMenu::aboutToShow, this, &QmitkDataNodeSurfaceRepresentationAction::OnMenuAboutShow); } void QmitkDataNodeSurfaceRepresentationAction::OnMenuAboutShow() { mitk::DataNode::Pointer dataNode = GetSelectedNode(); if (nullptr == dataNode) { return; } - mitk::EnumerationProperty* representationProp = dynamic_cast(dataNode->GetProperty("material.representation")); + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + mitk::EnumerationProperty* representationProp = dynamic_cast(dataNode->GetProperty("material.representation", baseRenderer)); if (nullptr == representationProp) { return; } menu()->clear(); QAction* tmp; for (mitk::EnumerationProperty::EnumConstIterator it = representationProp->Begin(); it != representationProp->End(); ++it) { tmp = menu()->addAction(QString::fromStdString(it->second)); tmp->setCheckable(true); if (it->second == representationProp->GetValueAsString()) { tmp->setChecked(true); } connect(tmp, &QAction::triggered, this, &QmitkDataNodeSurfaceRepresentationAction::OnActionTriggered); } } void QmitkDataNodeSurfaceRepresentationAction::OnActionTriggered(bool /*checked*/) { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } - mitk::EnumerationProperty* representationProp = dynamic_cast(dataNode->GetProperty("material.representation")); + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + mitk::EnumerationProperty* representationProp = dynamic_cast(dataNode->GetProperty("material.representation", baseRenderer)); if (nullptr == representationProp) { return; } QAction* senderAction = qobject_cast(QObject::sender()); if (nullptr == senderAction) { return; } std::string activatedItem = senderAction->text().toStdString(); if (activatedItem != representationProp->GetValueAsString()) { if (representationProp->IsValidEnumerationValue(activatedItem)) { representationProp->SetValue(activatedItem); representationProp->InvokeEvent(itk::ModifiedEvent()); representationProp->Modified(); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.h index 57abbf8e87..77ef9f1fbe 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeSurfaceRepresentationAction.h @@ -1,49 +1,47 @@ /*=================================================================== 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 QMITKDATANODESURFACEREPRESENTATIONACTION_H #define QMITKDATANODESURFACEREPRESENTATIONACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include class MITK_QT_APP QmitkDataNodeSurfaceRepresentationAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeSurfaceRepresentationAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeSurfaceRepresentationAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeSurfaceRepresentationAction() override; - private Q_SLOTS: void OnMenuAboutShow(); void OnActionTriggered(bool); protected: virtual void InitializeAction() override; }; #endif // QMITKDATANODESURFACEREPRESENTATIONACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp index 7dfac8d873..2f1190363c 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp @@ -1,79 +1,91 @@ /*=================================================================== 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 QmitkDataNodeTextureInterpolationAction::QmitkDataNodeTextureInterpolationAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Texture Interpolation")); InitializeAction(); } QmitkDataNodeTextureInterpolationAction::QmitkDataNodeTextureInterpolationAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Texture Interpolation")); InitializeAction(); } -QmitkDataNodeTextureInterpolationAction::~QmitkDataNodeTextureInterpolationAction() -{ - // nothing here -} - void QmitkDataNodeTextureInterpolationAction::InitializeAction() { setCheckable(true); connect(this, &QmitkDataNodeTextureInterpolationAction::toggled, this, &QmitkDataNodeTextureInterpolationAction::OnActionToggled); connect(this, &QmitkDataNodeTextureInterpolationAction::changed, this, &QmitkDataNodeTextureInterpolationAction::OnActionChanged); } void QmitkDataNodeTextureInterpolationAction::InitializeWithDataNode(const mitk::DataNode* dataNode) { + if (nullptr == dataNode) + { + setChecked(false); + return; + } + + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + bool textureInterpolation = false; - dataNode->GetBoolProperty("texture interpolation", textureInterpolation); + dataNode->GetBoolProperty("texture interpolation", textureInterpolation, baseRenderer); setChecked(textureInterpolation); } void QmitkDataNodeTextureInterpolationAction::OnActionToggled(bool checked) { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } - dataNode->SetBoolProperty("texture interpolation", checked); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + dataNode->SetBoolProperty("texture interpolation", checked, baseRenderer); + + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } void QmitkDataNodeTextureInterpolationAction::OnActionChanged() { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } InitializeWithDataNode(dataNode); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.h index 589c2b2f95..32ff4333a5 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.h @@ -1,51 +1,49 @@ /*=================================================================== 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 QMITKDATANODETEXTUREINTERPOLATIONACTION_H #define QMITKDATANODETEXTUREINTERPOLATIONACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include class MITK_QT_APP QmitkDataNodeTextureInterpolationAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeTextureInterpolationAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeTextureInterpolationAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeTextureInterpolationAction() override; - virtual void InitializeWithDataNode(const mitk::DataNode* dataNode) override; private Q_SLOTS: void OnActionChanged(); void OnActionToggled(bool); protected: virtual void InitializeAction() override; }; #endif // QMITKDATANODETEXTUREINTERPOLATIONACTION_H diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp index a093b26481..3a6478271f 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp @@ -1,98 +1,103 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include // mitk core #include // berry #include #include #include // namespace that contains the concrete action namespace ToggleVisibilityAction { - void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, QList selectedNodes) + void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, const QList& selectedNodes /*= QList()*/, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { bool isVisible; for (auto& node : selectedNodes) { if (node.IsNotNull()) { isVisible = false; - node->GetBoolProperty("visible", isVisible); - node->SetVisibility(!isVisible); + node->GetBoolProperty("visible", isVisible, baseRenderer); + node->SetVisibility(!isVisible, baseRenderer); } } berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + berry::IPreferences::Pointer preferences = prefService->GetSystemPreferences()->Node(QmitkDataNodeGlobalReinitAction::ACTION_ID); bool globalReinit = preferences->GetBool("Call global reinit if node visibility is changed", false); if (globalReinit) { GlobalReinitAction::Run(workbenchPartSite, dataStorage); } else { - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + if (nullptr == baseRenderer) + { + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + } } } } QmitkDataNodeToggleVisibilityAction::QmitkDataNodeToggleVisibilityAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Toggle visibility")); InitializeAction(); } QmitkDataNodeToggleVisibilityAction::QmitkDataNodeToggleVisibilityAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Toggle visibility")); InitializeAction(); } -QmitkDataNodeToggleVisibilityAction::~QmitkDataNodeToggleVisibilityAction() -{ - // nothing here -} - void QmitkDataNodeToggleVisibilityAction::InitializeAction() { connect(this, &QmitkDataNodeToggleVisibilityAction::triggered, this, &QmitkDataNodeToggleVisibilityAction::OnActionTriggered); } void QmitkDataNodeToggleVisibilityAction::OnActionTriggered(bool /*checked*/) { if (m_WorkbenchPartSite.Expired()) { return; } if (m_DataStorage.IsExpired()) { return; } - auto selectedNodes = GetSelectedNodes(); - ToggleVisibilityAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock(), selectedNodes); + mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); + + auto dataNodes = GetSelectedNodes(); + ToggleVisibilityAction::Run(m_WorkbenchPartSite.Lock(), m_DataStorage.Lock(), dataNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.h index 5cabb82e13..65aca1c442 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.h @@ -1,55 +1,54 @@ /*=================================================================== 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 QMITKDATANODETOGGLEVISIBILITYACTION_H #define QMITKDATANODETOGGLEVISIBILITYACTION_H #include #include "QmitkAbstractDataNodeAction.h" // qt #include namespace ToggleVisibilityAction { MITK_QT_APP void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, - QList selectedNodes); + const QList& selectedNodes = QList(), + mitk::BaseRenderer* baseRenderer = nullptr); } class MITK_QT_APP QmitkDataNodeToggleVisibilityAction : public QAction, public QmitkAbstractDataNodeAction { Q_OBJECT public: QmitkDataNodeToggleVisibilityAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeToggleVisibilityAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkDataNodeToggleVisibilityAction() override; - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; }; #endif // QMITKDATANODETOGGLEVISIBILITYACTION_H diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp index 513edecd85..ec3c8cc14e 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.cpp @@ -1,217 +1,238 @@ /*=================================================================== 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 "QmitkViewCoordinator.h" #include "QmitkAbstractView.h" #include #include #include #include #include QmitkViewCoordinator::QmitkViewCoordinator() : m_ActiveZombieView(nullptr) , m_ActiveRenderWindowPart(nullptr) , m_VisibleRenderWindowPart(nullptr) { } QmitkViewCoordinator::~QmitkViewCoordinator() { } void QmitkViewCoordinator::Start() { berry::PlatformUI::GetWorkbench()->AddWindowListener(this); QList wnds(berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows()); - for (QList::iterator i = wnds.begin(); - i != wnds.end(); ++i) + for (QList::iterator i = wnds.begin(); i != wnds.end(); ++i) { (*i)->GetPartService()->AddPartListener(this); } } void QmitkViewCoordinator::Stop() { if (!berry::PlatformUI::IsWorkbenchRunning()) return; berry::PlatformUI::GetWorkbench()->RemoveWindowListener(this); QList wnds(berry::PlatformUI::GetWorkbench()->GetWorkbenchWindows()); - for (QList::iterator i = wnds.begin(); - i != wnds.end(); ++i) + for (QList::iterator i = wnds.begin(); i != wnds.end(); ++i) { (*i)->GetPartService()->RemovePartListener(this); } } berry::IPartListener::Events::Types QmitkViewCoordinator::GetPartEventTypes() const { return berry::IPartListener::Events::ACTIVATED | berry::IPartListener::Events::DEACTIVATED | berry::IPartListener::Events::CLOSED | berry::IPartListener::Events::HIDDEN - | berry::IPartListener::Events::VISIBLE | berry::IPartListener::Events::OPENED; + | berry::IPartListener::Events::VISIBLE | berry::IPartListener::Events::OPENED + | berry::IPartListener::Events::INPUT_CHANGED; } -void QmitkViewCoordinator::PartActivated(const berry::IWorkbenchPartReference::Pointer& partRef ) +void QmitkViewCoordinator::PartActivated(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartActivated (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was activated - if ( mitk::IRenderWindowPart* renderPart = dynamic_cast(part) ) + if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (m_VisibleRenderWindowPart != renderPart) { RenderWindowPartActivated(renderPart); m_ActiveRenderWindowPart = renderPart; m_VisibleRenderWindowPart = renderPart; } } // Check if the activated part wants to be notified if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Activated(); } // Check if a zombie view has been activated. if (mitk::IZombieViewPart* zombieView = dynamic_cast(part)) { if (m_ActiveZombieView && (m_ActiveZombieView != zombieView)) { // Another zombie view has been activated. Tell the old one about it. m_ActiveZombieView->ActivatedZombieView(partRef); m_ActiveZombieView = zombieView; } } } -void QmitkViewCoordinator::PartDeactivated(const berry::IWorkbenchPartReference::Pointer& partRef ) +void QmitkViewCoordinator::PartDeactivated(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartDeactivated (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was deactivated if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (m_ActiveRenderWindowPart == renderPart) { this->RenderWindowPartDeactivated(renderPart); m_ActiveRenderWindowPart = nullptr; m_VisibleRenderWindowPart = nullptr; } } if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Deactivated(); } } -void QmitkViewCoordinator::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef ) +void QmitkViewCoordinator::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartOpened (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); if (mitk::IRenderWindowPartListener* renderWindowListener = dynamic_cast(part)) { m_RenderWindowListeners.insert(renderWindowListener); } } -void QmitkViewCoordinator::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef ) +void QmitkViewCoordinator::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartClosed (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); if (mitk::IRenderWindowPartListener* renderWindowListener = dynamic_cast(part)) { m_RenderWindowListeners.remove(renderWindowListener); } } -void QmitkViewCoordinator::PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef ) +void QmitkViewCoordinator::PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartHidden (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and if it is the currently active on. // Inform IRenderWindowPartListener views that it has been hidden. - if ( mitk::IRenderWindowPart* renderPart = dynamic_cast(part) ) + if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (!m_ActiveRenderWindowPart && m_VisibleRenderWindowPart == renderPart) { RenderWindowPartDeactivated(renderPart); m_VisibleRenderWindowPart = nullptr; } } if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Hidden(); } } -void QmitkViewCoordinator::PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef ) +void QmitkViewCoordinator::PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) { //MITK_INFO << "*** PartVisible (" << partRef->GetPart(false)->GetPartName() << ")"; berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); // Check for a render window part and inform IRenderWindowPartListener views // that it was activated - if ( mitk::IRenderWindowPart* renderPart = dynamic_cast(part) ) + if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { if (!m_ActiveRenderWindowPart) { RenderWindowPartActivated(renderPart); m_VisibleRenderWindowPart = renderPart; } } if (mitk::ILifecycleAwarePart* lifecycleAwarePart = dynamic_cast(part)) { lifecycleAwarePart->Visible(); } } -void QmitkViewCoordinator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderPart) +void QmitkViewCoordinator::PartInputChanged(const berry::IWorkbenchPartReference::Pointer& partRef) { - foreach (mitk::IRenderWindowPartListener* l, m_RenderWindowListeners) + berry::IWorkbenchPart* part = partRef->GetPart(false).GetPointer(); + + // Check for a render window part and inform IRenderWindowPartListener views + // that it was changed + if (mitk::IRenderWindowPart* renderPart = dynamic_cast(part)) { - l->RenderWindowPartActivated(renderPart); + if (!m_ActiveRenderWindowPart) + { + RenderWindowPartInputChanged(renderPart); + } } } -void QmitkViewCoordinator::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderPart) +void QmitkViewCoordinator::WindowOpened(const berry::IWorkbenchWindow::Pointer& window) { - foreach (mitk::IRenderWindowPartListener* l, m_RenderWindowListeners) + window->GetPartService()->AddPartListener(this); +} + +void QmitkViewCoordinator::WindowClosed(const berry::IWorkbenchWindow::Pointer& /*window*/) +{ +} + +void QmitkViewCoordinator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderPart) +{ + for (auto& listener : m_RenderWindowListeners) { - l->RenderWindowPartDeactivated(renderPart); + listener->RenderWindowPartActivated(renderPart); } } -void QmitkViewCoordinator::WindowClosed(const berry::IWorkbenchWindow::Pointer& /*window*/ ) +void QmitkViewCoordinator::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderPart) { + for (auto& listener : m_RenderWindowListeners) + { + listener->RenderWindowPartDeactivated(renderPart); + } } -void QmitkViewCoordinator::WindowOpened(const berry::IWorkbenchWindow::Pointer& window ) +void QmitkViewCoordinator::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderPart) { - window->GetPartService()->AddPartListener(this); + for (auto& listener : m_RenderWindowListeners) + { + listener->RenderWindowPartInputChanged(renderPart); + } } - diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.h index 398ee82f21..1be33f4a81 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.h +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkViewCoordinator.h @@ -1,122 +1,128 @@ /*=================================================================== 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 QmitkViewCoordinator_h #define QmitkViewCoordinator_h #include #include #include #include #include namespace mitk { struct IRenderWindowPart; struct IRenderWindowPartListener; struct IZombieViewPart; } class QmitkAbstractView; /** * A class which coordinates active QmitkAbstractView s, e.g. calling activated and hidden on them. */ class QmitkViewCoordinator : private berry::IPartListener, private berry::IWindowListener { public: /** * Add listener */ QmitkViewCoordinator(); /** * Remove listener */ ~QmitkViewCoordinator() override; void Start(); void Stop(); //#IPartListener methods (these methods internally call Activated() or other similar methods) /** * \see IPartListener::GetPartEventTypes() */ berry::IPartListener::Events::Types GetPartEventTypes() const override; /** * \see IPartListener::PartActivated() */ void PartActivated (const berry::IWorkbenchPartReference::Pointer& partRef) override; /** * \see IPartListener::PartDeactivated() */ void PartDeactivated(const berry::IWorkbenchPartReference::Pointer& /*partRef*/) override; /** * \see IPartListener::PartOpened() */ void PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** * \see IPartListener::PartClosed() */ void PartClosed (const berry::IWorkbenchPartReference::Pointer& partRef) override; /** * \see IPartListener::PartHidden() */ void PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** * \see IPartListener::PartVisible() */ void PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** - * Notifies this listener that the given window has been closed. - */ - void WindowClosed(const berry::IWorkbenchWindow::Pointer& window) override; + * \see IPartListener::PartInputChanged() + */ + void PartInputChanged(const berry::IWorkbenchPartReference::Pointer& partRef) override; /** - * Notifies this listener that the given window has been opened. + * Notifies this listener that the given window has been opened. + */ + void WindowOpened(const berry::IWorkbenchWindow::Pointer& window) override; + + /** + * Notifies this listener that the given window has been closed. */ - void WindowOpened(const berry::IWorkbenchWindow::Pointer& /*window*/) override; + void WindowClosed(const berry::IWorkbenchWindow::Pointer& window) override; private: void RenderWindowPartActivated(mitk::IRenderWindowPart* renderPart); void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderPart); + void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderPart); private: mitk::IZombieViewPart* m_ActiveZombieView; mitk::IRenderWindowPart* m_ActiveRenderWindowPart; mitk::IRenderWindowPart* m_VisibleRenderWindowPart; QSet m_RenderWindowListeners; }; #endif // QmitkViewCoordinator_h diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h index 2be976e22a..8974d8a1de 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h @@ -1,142 +1,142 @@ /*=================================================================== 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 QMITKDATAMANAGERVIEW_H_ -#define QMITKDATAMANAGERVIEW_H_ +#ifndef QMITKDATAMANAGERVIEW_H +#define QMITKDATAMANAGERVIEW_H #include // mitk core #include // berry plugin #include // mitk gui qt common plugin #include // mitk gui qt application #include // qt #include // forward declarations class QAction; class QModelIndex; class QTreeView; class QSignalMapper; class QmitkDnDFrameWidget; class QmitkDataStorageTreeModel; class QmitkDataManagerItemDelegate; class QmitkDataStorageFilterProxyModel; /** * @brief A view that shows all data nodes of the data storage in a qt tree view. * */ class MITK_QT_DATAMANAGER QmitkDataManagerView : public QmitkAbstractView { Q_OBJECT public: static const QString VIEW_ID; // = "org.mitk.views.datamanager" QmitkDataManagerView(); ~QmitkDataManagerView() override; public Q_SLOTS: // invoked when the berry preferences were changed void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; ////////////////////////////////////////////////////////////////////////// // Slots for Qt node tree signals ////////////////////////////////////////////////////////////////////////// /// When rows are inserted auto expand them void NodeTreeViewRowsInserted(const QModelIndex& parent, int start, int end); /// will setup m_CurrentRowCount void NodeTreeViewRowsRemoved(const QModelIndex& parent, int start, int end); /// Whenever the selection changes set the "selected" property respectively void NodeSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void OnNodeVisibilityChanged(); /// Opens the editor with the given id using the current data storage void ShowIn(const QString& editorId); protected: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; /// /// React to node changes. Overridden from QmitkAbstractView. /// void NodeChanged(const mitk::DataNode* node) override; protected: QWidget* m_Parent; QmitkDnDFrameWidget* m_DnDFrameWidget; /// /// \brief A plain widget as the base pane. /// QmitkDataStorageTreeModel* m_NodeTreeModel; QmitkDataStorageFilterProxyModel* m_FilterModel; mitk::NodePredicateBase::Pointer m_HelperObjectFilterPredicate; mitk::NodePredicateBase::Pointer m_NodeWithNoDataFilterPredicate; /// /// Holds the preferences for the data manager. /// berry::IBerryPreferences::Pointer m_DataManagerPreferencesNode; /// /// \brief The Table view to show the selected nodes. /// QTreeView* m_NodeTreeView; /// /// \brief The context menu that shows up when right clicking on a node. /// QmitkDataNodeContextMenu* m_DataNodeContextMenu; /// /// \brief flag indicating whether a surface created from a selected decimation is decimated with vtkQuadricDecimation or not /// bool m_SurfaceDecimation; /// Maps "Show in" actions to editor ids QSignalMapper* m_ShowInMapper; /// A list of "Show in" actions QList m_ShowInActions; /// saves the current amount of rows shown in the data manager size_t m_CurrentRowCount; QmitkDataManagerItemDelegate* m_ItemDelegate; private: QItemSelectionModel* GetDataNodeSelectionModel() const override; }; -#endif // QMITKDATAMANAGERVIEW_H_ +#endif // QMITKDATAMANAGERVIEW_H diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp index bb3258e4c8..f9c90b8740 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkNodeTableViewKeyFilter.cpp @@ -1,106 +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. ===================================================================*/ #include "QmitkNodeTableViewKeyFilter.h" #include "../QmitkDataManagerView.h" // mitk gui qt application plugin #include #include #include #include #include #include #include "berryIPreferencesService.h" #include "berryPlatform.h" // qt #include #include QmitkNodeTableViewKeyFilter::QmitkNodeTableViewKeyFilter(QObject *dataManagerView, mitk::DataStorage *dataStorage) : QObject(dataManagerView), m_DataStorage(dataStorage) { m_PreferencesService = berry::Platform::GetPreferencesService(); } bool QmitkNodeTableViewKeyFilter::eventFilter(QObject *obj, QEvent *event) { if (m_DataStorage.IsExpired()) { // standard event processing return QObject::eventFilter(obj, event); } auto dataStorage = m_DataStorage.Lock(); QmitkDataManagerView *dataManagerView = qobject_cast(this->parent()); if (event->type() == QEvent::KeyPress && dataManagerView) { berry::IPreferences::Pointer nodeTableKeyPrefs = m_PreferencesService->GetSystemPreferences()->Node("/DataManager/Hotkeys"); QKeySequence makeAllInvisible = QKeySequence(nodeTableKeyPrefs->Get("Make all nodes invisible", "Ctrl+V")); QKeySequence toggleVisibility = QKeySequence(nodeTableKeyPrefs->Get("Toggle visibility of selected nodes", "V")); QKeySequence deleteSelectedNodes = QKeySequence(nodeTableKeyPrefs->Get("Delete selected nodes", "Del")); QKeySequence reinit = QKeySequence(nodeTableKeyPrefs->Get("Reinit selected nodes", "R")); QKeySequence globalReinit = QKeySequence(nodeTableKeyPrefs->Get("Global reinit", "Ctrl+R")); QKeySequence showInfo = QKeySequence(nodeTableKeyPrefs->Get("Show node information", "Ctrl+I")); QKeyEvent *keyEvent = static_cast(event); QKeySequence keySequence = QKeySequence(keyEvent->modifiers() + keyEvent->key()); // if no modifier was pressed the sequence is now empty if (keySequence.isEmpty()) { keySequence = QKeySequence(keyEvent->key()); } - const auto& selectedNodes = AbstractDataNodeAction::GetSelectedNodes(dataManagerView->GetSite()); + auto selectedNodes = AbstractDataNodeAction::GetSelectedNodes(dataManagerView->GetSite()); if (keySequence == makeAllInvisible) { + if (selectedNodes.empty()) + { + // if no nodes are selected, hide all nodes of the data storage + auto nodeset = dataStorage->GetAll(); + for (auto it = nodeset->Begin(); it != nodeset->End(); ++it) + { + mitk::DataNode* node = it->Value(); + if (nullptr != node) + { + selectedNodes.push_back(node); + } + } + } + HideAllAction::Run(selectedNodes); return true; } - else if (keySequence == deleteSelectedNodes) + if (keySequence == deleteSelectedNodes) { RemoveAction::Run(dataManagerView->GetSite(), dataStorage, selectedNodes); return true; } - else if (keySequence == toggleVisibility) + if (keySequence == toggleVisibility) { ToggleVisibilityAction::Run(dataManagerView->GetSite(), dataStorage, selectedNodes); return true; } - else if (keySequence == reinit) + if (keySequence == reinit) { ReinitAction::Run(dataManagerView->GetSite(), dataStorage, selectedNodes); return true; } - else if (keySequence == globalReinit) + if (keySequence == globalReinit) { GlobalReinitAction::Run(dataManagerView->GetSite(), dataStorage); return true; } - else if (keySequence == showInfo) + if (keySequence == showInfo) { ShowDetailsAction::Run(selectedNodes); return true; } } // standard event processing return QObject::eventFilter(obj, event); } diff --git a/Plugins/org.mitk.gui.qt.ext/files.cmake b/Plugins/org.mitk.gui.qt.ext/files.cmake index f911d28d06..562bc5d984 100644 --- a/Plugins/org.mitk.gui.qt.ext/files.cmake +++ b/Plugins/org.mitk.gui.qt.ext/files.cmake @@ -1,59 +1,63 @@ set(SRC_CPP_FILES QmitkExtActionBarAdvisor.cpp QmitkExtWorkbenchWindowAdvisor.cpp QmitkExtFileSaveProjectAction.cpp QmitkOpenDicomEditorAction.cpp + QmitkOpenMxNMultiWidgetEditorAction.cpp + QmitkOpenStdMultiWidgetEditorAction.cpp ) set(INTERNAL_CPP_FILES QmitkAboutHandler.cpp QmitkAppInstancesPreferencePage.cpp QmitkExternalProgramsPreferencePage.cpp QmitkCommonExtPlugin.cpp QmitkInputDevicesPrefPage.cpp QmitkModuleView.cpp ) set(UI_FILES src/internal/QmitkAppInstancesPreferencePage.ui src/internal/QmitkExternalProgramsPreferencePage.ui ) set(MOC_H_FILES src/QmitkExtFileSaveProjectAction.h src/QmitkExtWorkbenchWindowAdvisor.h src/internal/QmitkAboutHandler.h src/internal/QmitkAppInstancesPreferencePage.h src/internal/QmitkExternalProgramsPreferencePage.h src/internal/QmitkCommonExtPlugin.h src/internal/QmitkExtWorkbenchWindowAdvisorHack.h src/internal/QmitkInputDevicesPrefPage.h src/internal/QmitkModuleView.h src/QmitkOpenDicomEditorAction.h + src/QmitkOpenMxNMultiWidgetEditorAction.h + src/QmitkOpenStdMultiWidgetEditorAction.h ) set(CACHED_RESOURCE_FILES # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench plugin.xml resources/ModuleView.png ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/org_mitk_gui_qt_ext.qrc resources/org_mitk_icons.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.ext/resources/Editor.png b/Plugins/org.mitk.gui.qt.ext/resources/Editor.png new file mode 100644 index 0000000000..8043b0e626 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.ext/resources/Editor.png differ diff --git a/Plugins/org.mitk.gui.qt.ext/resources/Slider_48.png b/Plugins/org.mitk.gui.qt.ext/resources/Slider_48.png deleted file mode 100644 index f2392b19e2..0000000000 Binary files a/Plugins/org.mitk.gui.qt.ext/resources/Slider_48.png and /dev/null differ diff --git a/Plugins/org.mitk.gui.qt.ext/resources/org_mitk_gui_qt_ext.qrc b/Plugins/org.mitk.gui.qt.ext/resources/org_mitk_gui_qt_ext.qrc index 007377ac7e..25c011d9dd 100644 --- a/Plugins/org.mitk.gui.qt.ext/resources/org_mitk_gui_qt_ext.qrc +++ b/Plugins/org.mitk.gui.qt.ext/resources/org_mitk_gui_qt_ext.qrc @@ -1,9 +1,10 @@ dicom.svg + Editor.png image_navigator.svg index.html xnat-icon.png view-manager.svg diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp index 5654196a91..e388709513 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.cpp @@ -1,1411 +1,1430 @@ /*=================================================================== 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 "QmitkExtWorkbenchWindowAdvisor.h" #include "QmitkExtActionBarAdvisor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include #include #include #include #include #include #include #include #include // UGLYYY #include "internal/QmitkExtWorkbenchWindowAdvisorHack.h" #include "internal/QmitkCommonExtPlugin.h" #include "mitkUndoController.h" #include "mitkVerboseLimitedLinearUndo.h" #include #include #include #include #include #include -QmitkExtWorkbenchWindowAdvisorHack - * QmitkExtWorkbenchWindowAdvisorHack::undohack = +QmitkExtWorkbenchWindowAdvisorHack* QmitkExtWorkbenchWindowAdvisorHack::undohack = new QmitkExtWorkbenchWindowAdvisorHack(); QString QmitkExtWorkbenchWindowAdvisor::QT_SETTINGS_FILENAME = "QtSettings.ini"; static bool USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS = false; class PartListenerForTitle: public berry::IPartListener { public: - PartListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : - windowAdvisor(wa) + PartListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) + : windowAdvisor(wa) { } Events::Types GetPartEventTypes() const override { return Events::ACTIVATED | Events::BROUGHT_TO_TOP | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartActivated(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartBroughtToTop(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref.Cast ()) { windowAdvisor->UpdateTitle(false); } } void PartClosed(const berry::IWorkbenchPartReference::Pointer& /*ref*/) override { windowAdvisor->UpdateTitle(false); } void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override { if (!windowAdvisor->lastActiveEditor.Expired() && ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) { windowAdvisor->UpdateTitle(true); } } void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override { if (!windowAdvisor->lastActiveEditor.Expired() && ref->GetPart(false) == windowAdvisor->lastActiveEditor.Lock()) { windowAdvisor->UpdateTitle(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; class PartListenerForViewNavigator: public berry::IPartListener { public: - PartListenerForViewNavigator(QAction* act) : - viewNavigatorAction(act) + PartListenerForViewNavigator(QAction* act) + : viewNavigatorAction(act) { } Events::Types GetPartEventTypes() const override { return Events::OPENED | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartOpened(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigatorview") { viewNavigatorAction->setChecked(true); } } void PartClosed(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigatorview") { viewNavigatorAction->setChecked(false); } } void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigatorview") { viewNavigatorAction->setChecked(true); } } void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.viewnavigatorview") { viewNavigatorAction->setChecked(false); } } private: QAction* viewNavigatorAction; }; class PartListenerForImageNavigator: public berry::IPartListener { public: - PartListenerForImageNavigator(QAction* act) : - imageNavigatorAction(act) + PartListenerForImageNavigator(QAction* act) + : imageNavigatorAction(act) { } Events::Types GetPartEventTypes() const override { return Events::OPENED | Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void PartOpened(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartClosed(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } void PartVisible(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(true); } } void PartHidden(const berry::IWorkbenchPartReference::Pointer& ref) override { if (ref->GetId()=="org.mitk.views.imagenavigator") { imageNavigatorAction->setChecked(false); } } private: QAction* imageNavigatorAction; }; class PerspectiveListenerForTitle: public berry::IPerspectiveListener { public: - PerspectiveListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) : - windowAdvisor(wa), perspectivesClosed(false) + PerspectiveListenerForTitle(QmitkExtWorkbenchWindowAdvisor* wa) + : windowAdvisor(wa) + , perspectivesClosed(false) { } Events::Types GetPerspectiveEventTypes() const override { if (USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS) { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED; } else { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED | Events::CLOSED | Events::OPENED; } } void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { windowAdvisor->UpdateTitle(false); } void PerspectiveSavedAs(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*oldPerspective*/, const berry::IPerspectiveDescriptor::Pointer& /*newPerspective*/) override { windowAdvisor->UpdateTitle(false); } void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { windowAdvisor->UpdateTitle(false); } void PerspectiveOpened(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { if (perspectivesClosed) { QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(true); } //GetViewRegistry()->Find("org.mitk.views.imagenavigator"); if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { windowAdvisor->openDicomEditorAction->setEnabled(true); } + if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) + { + windowAdvisor->openStdMultiWidgetEditorAction->setEnabled(true); + } + if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) + { + windowAdvisor->openMxNMultiWidgetEditorAction->setEnabled(true); + } + windowAdvisor->fileSaveProjectAction->setEnabled(true); windowAdvisor->closeProjectAction->setEnabled(true); windowAdvisor->undoAction->setEnabled(true); windowAdvisor->redoAction->setEnabled(true); windowAdvisor->imageNavigatorAction->setEnabled(true); windowAdvisor->viewNavigatorAction->setEnabled(true); windowAdvisor->resetPerspAction->setEnabled(true); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(true); } } perspectivesClosed = false; } void PerspectiveClosed(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { berry::IWorkbenchWindow::Pointer wnd = windowAdvisor->GetWindowConfigurer()->GetWindow(); bool allClosed = true; if (wnd->GetActivePage()) { QList perspectives(wnd->GetActivePage()->GetOpenPerspectives()); allClosed = perspectives.empty(); } if (allClosed) { perspectivesClosed = true; QListIterator i(windowAdvisor->viewActions); while (i.hasNext()) { i.next()->setEnabled(false); } if(windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { windowAdvisor->openDicomEditorAction->setEnabled(false); } + if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) + { + windowAdvisor->openStdMultiWidgetEditorAction->setEnabled(false); + } + if (windowAdvisor->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) + { + windowAdvisor->openMxNMultiWidgetEditorAction->setEnabled(false); + } + windowAdvisor->fileSaveProjectAction->setEnabled(false); windowAdvisor->closeProjectAction->setEnabled(false); windowAdvisor->undoAction->setEnabled(false); windowAdvisor->redoAction->setEnabled(false); windowAdvisor->imageNavigatorAction->setEnabled(false); windowAdvisor->viewNavigatorAction->setEnabled(false); windowAdvisor->resetPerspAction->setEnabled(false); if( windowAdvisor->GetShowClosePerspectiveMenuItem() ) { windowAdvisor->closePerspAction->setEnabled(false); } } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; bool perspectivesClosed; }; class PerspectiveListenerForMenu: public berry::IPerspectiveListener { public: - PerspectiveListenerForMenu(QmitkExtWorkbenchWindowAdvisor* wa) : - windowAdvisor(wa) + PerspectiveListenerForMenu(QmitkExtWorkbenchWindowAdvisor* wa) + : windowAdvisor(wa) { } Events::Types GetPerspectiveEventTypes() const override { return Events::ACTIVATED | Events::DEACTIVATED; } void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& perspective) override { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(true); } } void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& perspective) override { QAction* action = windowAdvisor->mapPerspIdToAction[perspective->GetId()]; if (action) { action->setChecked(false); } } private: QmitkExtWorkbenchWindowAdvisor* windowAdvisor; }; QmitkExtWorkbenchWindowAdvisor::QmitkExtWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, - berry::IWorkbenchWindowConfigurer::Pointer configurer) : -berry::WorkbenchWindowAdvisor(configurer), - lastInput(nullptr), - wbAdvisor(wbAdvisor), - showViewToolbar(true), - showPerspectiveToolbar(false), - showVersionInfo(false), - showMitkVersionInfo(true), - showViewMenuItem(true), - showNewWindowMenuItem(false), - showClosePerspectiveMenuItem(true), - viewNavigatorFound(false), - showMemoryIndicator(true), - dropTargetListener(new QmitkDefaultDropTargetListener) + berry::IWorkbenchWindowConfigurer::Pointer configurer) + : berry::WorkbenchWindowAdvisor(configurer) + , lastInput(nullptr) + , wbAdvisor(wbAdvisor) + , showViewToolbar(true) + , showPerspectiveToolbar(false) + , showVersionInfo(true) + , showMitkVersionInfo(true) + , showViewMenuItem(true) + , showNewWindowMenuItem(false) + , showClosePerspectiveMenuItem(true) + , viewNavigatorFound(false) + , showMemoryIndicator(true) + , dropTargetListener(new QmitkDefaultDropTargetListener) { productName = QCoreApplication::applicationName(); viewExcludeList.push_back("org.mitk.views.viewnavigatorview"); } QmitkExtWorkbenchWindowAdvisor::~QmitkExtWorkbenchWindowAdvisor() { } -berry::ActionBarAdvisor::Pointer QmitkExtWorkbenchWindowAdvisor::CreateActionBarAdvisor( - berry::IActionBarConfigurer::Pointer configurer) +berry::ActionBarAdvisor::Pointer QmitkExtWorkbenchWindowAdvisor::CreateActionBarAdvisor(berry::IActionBarConfigurer::Pointer configurer) { if (USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS) { - berry::ActionBarAdvisor::Pointer actionBarAdvisor( - new QmitkExtActionBarAdvisor(configurer)); + berry::ActionBarAdvisor::Pointer actionBarAdvisor(new QmitkExtActionBarAdvisor(configurer)); return actionBarAdvisor; } else { return berry::WorkbenchWindowAdvisor::CreateActionBarAdvisor(configurer); } } QWidget* QmitkExtWorkbenchWindowAdvisor::CreateEmptyWindowContents(QWidget* parent) { QWidget* parentWidget = static_cast(parent); auto label = new QLabel(parentWidget); label->setText("No perspectives are open. Open a perspective in the Window->Open Perspective menu."); label->setContentsMargins(10,10,10,10); label->setAlignment(Qt::AlignTop); label->setEnabled(false); parentWidget->layout()->addWidget(label); return label; } void QmitkExtWorkbenchWindowAdvisor::ShowClosePerspectiveMenuItem(bool show) { showClosePerspectiveMenuItem = show; } bool QmitkExtWorkbenchWindowAdvisor::GetShowClosePerspectiveMenuItem() { return showClosePerspectiveMenuItem; } void QmitkExtWorkbenchWindowAdvisor::ShowMemoryIndicator(bool show) { showMemoryIndicator = show; } bool QmitkExtWorkbenchWindowAdvisor::GetShowMemoryIndicator() { return showMemoryIndicator; } void QmitkExtWorkbenchWindowAdvisor::ShowNewWindowMenuItem(bool show) { showNewWindowMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewToolbar(bool show) { showViewToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowViewMenuItem(bool show) { showViewMenuItem = show; } void QmitkExtWorkbenchWindowAdvisor::ShowPerspectiveToolbar(bool show) { showPerspectiveToolbar = show; } void QmitkExtWorkbenchWindowAdvisor::ShowVersionInfo(bool show) { showVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::ShowMitkVersionInfo(bool show) { showMitkVersionInfo = show; } void QmitkExtWorkbenchWindowAdvisor::SetProductName(const QString& product) { productName = product; } void QmitkExtWorkbenchWindowAdvisor::SetWindowIcon(const QString& wndIcon) { windowIcon = wndIcon; } void QmitkExtWorkbenchWindowAdvisor::PostWindowCreate() { // very bad hack... - berry::IWorkbenchWindow::Pointer window = - this->GetWindowConfigurer()->GetWindow(); - QMainWindow* mainWindow = - qobject_cast (window->GetShell()->GetControl()); + berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); + QMainWindow* mainWindow = qobject_cast (window->GetShell()->GetControl()); if (!windowIcon.isEmpty()) { mainWindow->setWindowIcon(QIcon(windowIcon)); } mainWindow->setContextMenuPolicy(Qt::PreventContextMenu); // Load icon theme QIcon::setThemeSearchPaths(QStringList() << QStringLiteral(":/org_mitk_icons/icons/")); QIcon::setThemeName(QStringLiteral("awesome")); // ==== Application menu ============================ QMenuBar* menuBar = mainWindow->menuBar(); menuBar->setContextMenuPolicy(Qt::PreventContextMenu); #ifdef __APPLE__ menuBar->setNativeMenuBar(true); #else menuBar->setNativeMenuBar(false); #endif auto basePath = QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/"); auto fileOpenAction = new QmitkFileOpenAction(berry::QtStyleManager::ThemeIcon(basePath + "document-open.svg"), window); fileOpenAction->setShortcut(QKeySequence::Open); auto fileSaveAction = new QmitkFileSaveAction(berry::QtStyleManager::ThemeIcon(basePath + "document-save.svg"), window); fileSaveAction->setShortcut(QKeySequence::Save); fileSaveProjectAction = new QmitkExtFileSaveProjectAction(window); fileSaveProjectAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "document-save.svg")); closeProjectAction = new QmitkCloseProjectAction(window); closeProjectAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "edit-delete.svg")); auto perspGroup = new QActionGroup(menuBar); std::map VDMap; // sort elements (converting vector to map...) QList::const_iterator iter; berry::IViewRegistry* viewRegistry = berry::PlatformUI::GetWorkbench()->GetViewRegistry(); const QList viewDescriptors = viewRegistry->GetViews(); bool skip = false; for (iter = viewDescriptors.begin(); iter != viewDescriptors.end(); ++iter) { // if viewExcludeList is set, it contains the id-strings of view, which // should not appear as an menu-entry in the menu if (viewExcludeList.size() > 0) { for (int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } if ((*iter)->GetId() == "org.blueberry.ui.internal.introview") continue; if ((*iter)->GetId() == "org.mitk.views.imagenavigator") continue; if ((*iter)->GetId() == "org.mitk.views.viewnavigatorview") continue; - std::pair p( - (*iter)->GetLabel(), (*iter)); + std::pair p((*iter)->GetLabel(), (*iter)); VDMap.insert(p); } - std::map::const_iterator - MapIter; + std::map::const_iterator MapIter; for (MapIter = VDMap.begin(); MapIter != VDMap.end(); ++MapIter) { - berry::QtShowViewAction* viewAction = new berry::QtShowViewAction(window, - (*MapIter).second); + berry::QtShowViewAction* viewAction = new berry::QtShowViewAction(window, (*MapIter).second); viewActions.push_back(viewAction); } if (!USE_EXPERIMENTAL_COMMAND_CONTRIBUTIONS) { QMenu* fileMenu = menuBar->addMenu("&File"); fileMenu->setObjectName("FileMenu"); fileMenu->addAction(fileOpenAction); fileMenu->addAction(fileSaveAction); fileMenu->addAction(fileSaveProjectAction); fileMenu->addAction(closeProjectAction); fileMenu->addSeparator(); QAction* fileExitAction = new QmitkFileExitAction(window); fileExitAction->setIcon(berry::QtStyleManager::ThemeIcon(basePath + "system-log-out.svg")); fileExitAction->setShortcut(QKeySequence::Quit); fileExitAction->setObjectName("QmitkFileExitAction"); fileMenu->addAction(fileExitAction); // another bad hack to get an edit/undo menu... QMenu* editMenu = menuBar->addMenu("&Edit"); undoAction = editMenu->addAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-undo.svg"), "&Undo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onUndo()), QKeySequence("CTRL+Z")); undoAction->setToolTip("Undo the last action (not supported by all modules)"); redoAction = editMenu->addAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-redo.svg"), "&Redo", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onRedo()), QKeySequence("CTRL+Y")); redoAction->setToolTip("execute the last action that was undone again (not supported by all modules)"); // ==== Window Menu ========================== QMenu* windowMenu = menuBar->addMenu("Window"); if (showNewWindowMenuItem) { windowMenu->addAction("&New Window", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onNewWindow())); windowMenu->addSeparator(); } QMenu* perspMenu = windowMenu->addMenu("&Open Perspective"); QMenu* viewMenu = nullptr; if (showViewMenuItem) { viewMenu = windowMenu->addMenu("Show &View"); viewMenu->setObjectName("Show View"); } windowMenu->addSeparator(); resetPerspAction = windowMenu->addAction("&Reset Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onResetPerspective())); if(showClosePerspectiveMenuItem) closePerspAction = windowMenu->addAction("&Close Perspective", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onClosePerspective())); windowMenu->addSeparator(); windowMenu->addAction("&Preferences...", QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onEditPreferences()), QKeySequence("CTRL+P")); // fill perspective menu berry::IPerspectiveRegistry* perspRegistry = window->GetWorkbench()->GetPerspectiveRegistry(); QList perspectives( perspRegistry->GetPerspectives()); skip = false; for (QList::iterator perspIt = perspectives.begin(); perspIt != perspectives.end(); ++perspIt) { // if perspectiveExcludeList is set, it contains the id-strings of perspectives, which // should not appear as an menu-entry in the perspective menu if (perspectiveExcludeList.size() > 0) { for (int i=0; iGetId()) { skip = true; break; } } if (skip) { skip = false; continue; } } - QAction* perspAction = new berry::QtOpenPerspectiveAction(window, - *perspIt, perspGroup); + QAction* perspAction = new berry::QtOpenPerspectiveAction(window, *perspIt, perspGroup); mapPerspIdToAction.insert((*perspIt)->GetId(), perspAction); } perspMenu->addActions(perspGroup->actions()); if (showViewMenuItem) { for (auto viewAction : viewActions) { viewMenu->addAction(viewAction); } } // ===== Help menu ==================================== QMenu* helpMenu = menuBar->addMenu("&Help"); helpMenu->addAction("&Welcome",this, SLOT(onIntro())); helpMenu->addAction("&Open Help Perspective", this, SLOT(onHelpOpenHelpPerspective())); helpMenu->addAction("&Context Help",this, SLOT(onHelp()), QKeySequence("F1")); helpMenu->addAction("&About",this, SLOT(onAbout())); // ===================================================== } else { undoAction = new QmitkUndoAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-undo.svg"), nullptr); undoAction->setShortcut(QKeySequence::Undo); redoAction = new QmitkRedoAction(berry::QtStyleManager::ThemeIcon(basePath + "edit-redo.svg"), nullptr); redoAction->setShortcut(QKeySequence::Redo); } // toolbar for showing file open, undo, redo and other main actions auto mainActionsToolBar = new QToolBar; mainActionsToolBar->setObjectName("mainActionsToolBar"); mainActionsToolBar->setContextMenuPolicy(Qt::PreventContextMenu); #ifdef __APPLE__ mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextUnderIcon ); #else mainActionsToolBar->setToolButtonStyle ( Qt::ToolButtonTextBesideIcon ); #endif basePath = QStringLiteral(":/org.mitk.gui.qt.ext/"); imageNavigatorAction = new QAction(berry::QtStyleManager::ThemeIcon(basePath + "image_navigator.svg"), "&Image Navigator", nullptr); bool imageNavigatorViewFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.imagenavigator"); - if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) + if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { openDicomEditorAction = new QmitkOpenDicomEditorAction(berry::QtStyleManager::ThemeIcon(basePath + "dicom.svg"), window); } + if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) + { + openStdMultiWidgetEditorAction = new QmitkOpenStdMultiWidgetEditorAction(QIcon(":/org.mitk.gui.qt.ext/Editor.png"), window); + } + if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) + { + openMxNMultiWidgetEditorAction = new QmitkOpenMxNMultiWidgetEditorAction(QIcon(":/org.mitk.gui.qt.ext/Editor.png"), window); + } if (imageNavigatorViewFound) { QObject::connect(imageNavigatorAction, SIGNAL(triggered(bool)), QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onImageNavigator())); imageNavigatorAction->setCheckable(true); // add part listener for image navigator imageNavigatorPartListener.reset(new PartListenerForImageNavigator(imageNavigatorAction)); window->GetPartService()->AddPartListener(imageNavigatorPartListener.data()); - berry::IViewPart::Pointer imageNavigatorView = - window->GetActivePage()->FindView("org.mitk.views.imagenavigator"); + berry::IViewPart::Pointer imageNavigatorView = window->GetActivePage()->FindView("org.mitk.views.imagenavigator"); imageNavigatorAction->setChecked(false); if (imageNavigatorView) { bool isImageNavigatorVisible = window->GetActivePage()->IsPartVisible(imageNavigatorView); if (isImageNavigatorVisible) imageNavigatorAction->setChecked(true); } imageNavigatorAction->setToolTip("Toggle image navigator for navigating through image"); } viewNavigatorAction = new QAction(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/org.mitk.gui.qt.ext/view-manager.svg")),"&View Navigator", nullptr); viewNavigatorFound = window->GetWorkbench()->GetViewRegistry()->Find("org.mitk.views.viewnavigatorview"); if (viewNavigatorFound) { QObject::connect(viewNavigatorAction, SIGNAL(triggered(bool)), QmitkExtWorkbenchWindowAdvisorHack::undohack, SLOT(onViewNavigator())); viewNavigatorAction->setCheckable(true); // add part listener for view navigator viewNavigatorPartListener.reset(new PartListenerForViewNavigator(viewNavigatorAction)); window->GetPartService()->AddPartListener(viewNavigatorPartListener.data()); - berry::IViewPart::Pointer viewnavigatorview = - window->GetActivePage()->FindView("org.mitk.views.viewnavigatorview"); + berry::IViewPart::Pointer viewnavigatorview = window->GetActivePage()->FindView("org.mitk.views.viewnavigatorview"); viewNavigatorAction->setChecked(false); if (viewnavigatorview) { bool isViewNavigatorVisible = window->GetActivePage()->IsPartVisible(viewnavigatorview); if (isViewNavigatorVisible) viewNavigatorAction->setChecked(true); } viewNavigatorAction->setToolTip("Toggle View Navigator"); } mainActionsToolBar->addAction(fileOpenAction); mainActionsToolBar->addAction(fileSaveProjectAction); mainActionsToolBar->addAction(closeProjectAction); mainActionsToolBar->addAction(undoAction); mainActionsToolBar->addAction(redoAction); if(this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.dicomeditor")) { mainActionsToolBar->addAction(openDicomEditorAction); } + if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.stdmultiwidget")) + { + mainActionsToolBar->addAction(openStdMultiWidgetEditorAction); + } + if (this->GetWindowConfigurer()->GetWindow()->GetWorkbench()->GetEditorRegistry()->FindEditor("org.mitk.editors.mxnmultiwidget")) + { + mainActionsToolBar->addAction(openMxNMultiWidgetEditorAction); + } + if (imageNavigatorViewFound) { mainActionsToolBar->addAction(imageNavigatorAction); } if (viewNavigatorFound) { mainActionsToolBar->addAction(viewNavigatorAction); } mainWindow->addToolBar(mainActionsToolBar); // ==== Perspective Toolbar ================================== auto qPerspectiveToolbar = new QToolBar; qPerspectiveToolbar->setObjectName("perspectiveToolBar"); if (showPerspectiveToolbar) { qPerspectiveToolbar->addActions(perspGroup->actions()); mainWindow->addToolBar(qPerspectiveToolbar); } else delete qPerspectiveToolbar; if (showViewToolbar) { auto prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); berry::IPreferences::Pointer stylePrefs = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); bool showCategoryNames = stylePrefs->GetBool(berry::QtPreferences::QT_SHOW_TOOLBAR_CATEGORY_NAMES, true); // Order view descriptors by category QMultiMap categoryViewDescriptorMap; for (auto labelViewDescriptorPair : VDMap) { auto viewDescriptor = labelViewDescriptorPair.second; auto category = !viewDescriptor->GetCategoryPath().isEmpty() ? viewDescriptor->GetCategoryPath().back() : QString(); categoryViewDescriptorMap.insert(category, viewDescriptor); } // Create a separate toolbar for each category for (auto category : categoryViewDescriptorMap.uniqueKeys()) { auto viewDescriptorsInCurrentCategory = categoryViewDescriptorMap.values(category); if (!viewDescriptorsInCurrentCategory.isEmpty()) { auto toolbar = new QToolBar; toolbar->setObjectName(category + " View Toolbar"); mainWindow->addToolBar(toolbar); if (showCategoryNames && !category.isEmpty()) { auto categoryButton = new QToolButton; categoryButton->setToolButtonStyle(Qt::ToolButtonTextOnly); categoryButton->setText(category); categoryButton->setStyleSheet("background: transparent; margin: 0; padding: 0;"); toolbar->addWidget(categoryButton); connect(categoryButton, &QToolButton::clicked, [toolbar]() { for (QWidget* widget : toolbar->findChildren()) { if (QStringLiteral("qt_toolbar_ext_button") == widget->objectName() && widget->isVisible()) { QMouseEvent pressEvent(QEvent::MouseButtonPress, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QApplication::sendEvent(widget, &pressEvent); QApplication::sendEvent(widget, &releaseEvent); } } }); } for (auto viewDescriptor : viewDescriptorsInCurrentCategory) { auto viewAction = new berry::QtShowViewAction(window, viewDescriptor); toolbar->addAction(viewAction); } } } } QSettings settings(GetQSettingsFile(), QSettings::IniFormat); mainWindow->restoreState(settings.value("ToolbarPosition").toByteArray()); auto qStatusBar = new QStatusBar(); //creating a QmitkStatusBar for Output on the QStatusBar and connecting it with the MainStatusBar auto statusBar = new QmitkStatusBar(qStatusBar); //disabling the SizeGrip in the lower right corner statusBar->SetSizeGripEnabled(false); auto progBar = new QmitkProgressBar(); qStatusBar->addPermanentWidget(progBar, 0); progBar->hide(); // progBar->AddStepsToDo(2); // progBar->Progress(1); mainWindow->setStatusBar(qStatusBar); if (showMemoryIndicator) { auto memoryIndicator = new QmitkMemoryUsageIndicatorView(); qStatusBar->addPermanentWidget(memoryIndicator, 0); } } void QmitkExtWorkbenchWindowAdvisor::PreWindowOpen() { berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); // show the shortcut bar and progress indicator, which are hidden by // default //configurer->SetShowPerspectiveBar(true); //configurer->SetShowFastViewBars(true); //configurer->SetShowProgressIndicator(true); // // add the drag and drop support for the editor area // configurer.addEditorAreaTransfer(EditorInputTransfer.getInstance()); // configurer.addEditorAreaTransfer(ResourceTransfer.getInstance()); // configurer.addEditorAreaTransfer(FileTransfer.getInstance()); // configurer.addEditorAreaTransfer(MarkerTransfer.getInstance()); // configurer.configureEditorAreaDropListener(new EditorAreaDropAdapter( // configurer.getWindow())); this->HookTitleUpdateListeners(configurer); menuPerspectiveListener.reset(new PerspectiveListenerForMenu(this)); configurer->GetWindow()->AddPerspectiveListener(menuPerspectiveListener.data()); configurer->AddEditorAreaTransfer(QStringList("text/uri-list")); configurer->ConfigureEditorAreaDropListener(dropTargetListener.data()); } void QmitkExtWorkbenchWindowAdvisor::PostWindowOpen() { berry::WorkbenchWindowAdvisor::PostWindowOpen(); // Force Rendering Window Creation on startup. berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); ctkServiceReference serviceRef = context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService *dsService = context->getService(serviceRef); if (dsService) { mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); mitk::DataStorageEditorInput::Pointer dsInput(new mitk::DataStorageEditorInput(dsRef)); mitk::WorkbenchUtil::OpenEditor(configurer->GetWindow()->GetActivePage(),dsInput); } } } void QmitkExtWorkbenchWindowAdvisor::onIntro() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onIntro(); } void QmitkExtWorkbenchWindowAdvisor::onHelp() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelp(); } void QmitkExtWorkbenchWindowAdvisor::onHelpOpenHelpPerspective() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onHelpOpenHelpPerspective(); } void QmitkExtWorkbenchWindowAdvisor::onAbout() { QmitkExtWorkbenchWindowAdvisorHack::undohack->onAbout(); } //-------------------------------------------------------------------------------- // Ugly hack from here on. Feel free to delete when command framework // and undo buttons are done. //-------------------------------------------------------------------------------- -QmitkExtWorkbenchWindowAdvisorHack::QmitkExtWorkbenchWindowAdvisorHack() : QObject() +QmitkExtWorkbenchWindowAdvisorHack::QmitkExtWorkbenchWindowAdvisorHack() + : QObject() { } QmitkExtWorkbenchWindowAdvisorHack::~QmitkExtWorkbenchWindowAdvisorHack() { } void QmitkExtWorkbenchWindowAdvisorHack::onUndo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { - mitk::VerboseLimitedLinearUndo::StackDescription descriptions = - verboseundo->GetUndoDescriptions(); + mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetUndoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Undo " << descriptions.front().second; } } model->Undo(); } else { MITK_ERROR << "No undo model instantiated"; } } void QmitkExtWorkbenchWindowAdvisorHack::onRedo() { mitk::UndoModel* model = mitk::UndoController::GetCurrentUndoModel(); if (model) { if (mitk::VerboseLimitedLinearUndo* verboseundo = dynamic_cast( model )) { - mitk::VerboseLimitedLinearUndo::StackDescription descriptions = - verboseundo->GetRedoDescriptions(); + mitk::VerboseLimitedLinearUndo::StackDescription descriptions = verboseundo->GetRedoDescriptions(); if (descriptions.size() >= 1) { MITK_INFO << "Redo " << descriptions.front().second; } } model->Redo(); } else { MITK_ERROR << "No undo model instantiated"; } } // safe calls to the complete chain // berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.imagenavigator"); // to cover for all possible cases of closed pages etc. static void SafeHandleNavigatorView(QString view_query_name) { berry::IWorkbench* wbench = berry::PlatformUI::GetWorkbench(); if( wbench == nullptr ) return; berry::IWorkbenchWindow::Pointer wbench_window = wbench->GetActiveWorkbenchWindow(); if( wbench_window.IsNull() ) return; berry::IWorkbenchPage::Pointer wbench_page = wbench_window->GetActivePage(); if( wbench_page.IsNull() ) return; auto wbench_view = wbench_page->FindView( view_query_name ); if( wbench_view.IsNotNull() ) { bool isViewVisible = wbench_page->IsPartVisible( wbench_view ); if( isViewVisible ) { wbench_page->HideView( wbench_view ); return; } } wbench_page->ShowView( view_query_name ); } void QmitkExtWorkbenchWindowAdvisorHack::onImageNavigator() { // show/hide ImageNavigatorView SafeHandleNavigatorView("org.mitk.views.imagenavigator"); } void QmitkExtWorkbenchWindowAdvisorHack::onViewNavigator() { // show/hide viewnavigatorView SafeHandleNavigatorView("org.mitk.views.viewnavigatorview"); } void QmitkExtWorkbenchWindowAdvisorHack::onEditPreferences() { QmitkPreferencesDialog _PreferencesDialog(QApplication::activeWindow()); _PreferencesDialog.exec(); } void QmitkExtWorkbenchWindowAdvisorHack::onQuit() { berry::PlatformUI::GetWorkbench()->Close(); } void QmitkExtWorkbenchWindowAdvisorHack::onResetPerspective() { berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkExtWorkbenchWindowAdvisorHack::onClosePerspective() { - berry::IWorkbenchPage::Pointer - page = + berry::IWorkbenchPage::Pointer page = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); page->ClosePerspective(page->GetPerspective(), true, true); } void QmitkExtWorkbenchWindowAdvisorHack::onNewWindow() { berry::PlatformUI::GetWorkbench()->OpenWorkbenchWindow(nullptr); } void QmitkExtWorkbenchWindowAdvisorHack::onIntro() { bool hasIntro = berry::PlatformUI::GetWorkbench()->GetIntroManager()->HasIntro(); if (!hasIntro) { QRegExp reg("(.*)(\\n)*"); QRegExp reg2("(\\n)*(.*)"); QFile file(":/org.mitk.gui.qt.ext/index.html"); file.open(QIODevice::ReadOnly | QIODevice::Text); //text file only for reading QString text = QString(file.readAll()); file.close(); QString title = text; title.replace(reg, ""); title.replace(reg2, ""); std::cout << title.toStdString() << std::endl; QMessageBox::information(nullptr, title, text, "Close"); } else { berry::PlatformUI::GetWorkbench()->GetIntroManager()->ShowIntro( berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(), false); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelp() { ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); if (context == nullptr) { MITK_WARN << "Plugin context not set, unable to open context help"; return; } // Check if the org.blueberry.ui.qt.help plug-in is installed and started QList > plugins = context->getPlugins(); foreach(QSharedPointer p, plugins) { if (p->getSymbolicName() == "org.blueberry.ui.qt.help") { if (p->getState() != ctkPlugin::ACTIVE) { // try to activate the plug-in explicitly try { p->start(ctkPlugin::START_TRANSIENT); } catch (const ctkPluginException& pe) { MITK_ERROR << "Activating org.blueberry.ui.qt.help failed: " << pe.what(); return; } } } } ctkServiceReference eventAdminRef = context->getServiceReference(); ctkEventAdmin* eventAdmin = nullptr; if (eventAdminRef) { eventAdmin = context->getService(eventAdminRef); } if (eventAdmin == nullptr) { MITK_WARN << "ctkEventAdmin service not found. Unable to open context help"; } else { ctkEvent ev("org/blueberry/ui/help/CONTEXTHELP_REQUESTED"); eventAdmin->postEvent(ev); } } void QmitkExtWorkbenchWindowAdvisorHack::onHelpOpenHelpPerspective() { berry::PlatformUI::GetWorkbench()->ShowPerspective("org.blueberry.perspectives.help", berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()); } void QmitkExtWorkbenchWindowAdvisorHack::onAbout() { - auto aboutDialog = new QmitkAboutDialog(QApplication::activeWindow(),nullptr); + auto aboutDialog = new QmitkAboutDialog(QApplication::activeWindow(),nullptr); aboutDialog->open(); } -void QmitkExtWorkbenchWindowAdvisor::HookTitleUpdateListeners( - berry::IWorkbenchWindowConfigurer::Pointer configurer) +void QmitkExtWorkbenchWindowAdvisor::HookTitleUpdateListeners(berry::IWorkbenchWindowConfigurer::Pointer configurer) { // hook up the listeners to update the window title titlePartListener.reset(new PartListenerForTitle(this)); titlePerspectiveListener.reset(new PerspectiveListenerForTitle(this)); editorPropertyListener.reset(new berry::PropertyChangeIntAdapter< QmitkExtWorkbenchWindowAdvisor>(this, &QmitkExtWorkbenchWindowAdvisor::PropertyChange)); // configurer.getWindow().addPageListener(new IPageListener() { // public void pageActivated(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageClosed(IWorkbenchPage page) { // updateTitle(false); // } // // public void pageOpened(IWorkbenchPage page) { // // do nothing // } // }); configurer->GetWindow()->AddPerspectiveListener(titlePerspectiveListener.data()); configurer->GetWindow()->GetPartService()->AddPartListener(titlePartListener.data()); } QString QmitkExtWorkbenchWindowAdvisor::ComputeTitle() { - berry::IWorkbenchWindowConfigurer::Pointer configurer = - GetWindowConfigurer(); - berry::IWorkbenchPage::Pointer currentPage = - configurer->GetWindow()->GetActivePage(); + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); + berry::IWorkbenchPage::Pointer currentPage = configurer->GetWindow()->GetActivePage(); berry::IEditorPart::Pointer activeEditor; if (currentPage) { activeEditor = lastActiveEditor.Lock(); } QString title; berry::IProduct::Pointer product = berry::Platform::GetProduct(); if (product.IsNotNull()) { title = product->GetName(); } if (title.isEmpty()) { // instead of the product name, we use a custom variable for now title = productName; } if(showMitkVersionInfo) { QString mitkVersionInfo = MITK_REVISION_DESC; if(mitkVersionInfo.isEmpty()) mitkVersionInfo = MITK_VERSION_STRING; title += " " + mitkVersionInfo; } if (showVersionInfo) { // add version informatioin QString versions = QString(" (ITK %1.%2.%3 | VTK %4.%5.%6 | Qt %7)") .arg(ITK_VERSION_MAJOR).arg(ITK_VERSION_MINOR).arg(ITK_VERSION_PATCH) .arg(VTK_MAJOR_VERSION).arg(VTK_MINOR_VERSION).arg(VTK_BUILD_VERSION) .arg(QT_VERSION_STR); title += versions; } if (currentPage) { if (activeEditor) { lastEditorTitle = activeEditor->GetTitleToolTip(); if (!lastEditorTitle.isEmpty()) title = lastEditorTitle + " - " + title; } - berry::IPerspectiveDescriptor::Pointer persp = - currentPage->GetPerspective(); + berry::IPerspectiveDescriptor::Pointer persp = currentPage->GetPerspective(); QString label = ""; if (persp) { label = persp->GetLabel(); } berry::IAdaptable* input = currentPage->GetInput(); if (input && input != wbAdvisor->GetDefaultPageInput()) { label = currentPage->GetLabel(); } if (!label.isEmpty()) { title = label + " - " + title; } } title += " (Not for use in diagnosis or treatment of patients)"; return title; } void QmitkExtWorkbenchWindowAdvisor::RecomputeTitle() { - berry::IWorkbenchWindowConfigurer::Pointer configurer = - GetWindowConfigurer(); + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); QString oldTitle = configurer->GetTitle(); QString newTitle = ComputeTitle(); if (newTitle != oldTitle) { configurer->SetTitle(newTitle); } } void QmitkExtWorkbenchWindowAdvisor::UpdateTitle(bool editorHidden) { - berry::IWorkbenchWindowConfigurer::Pointer configurer = - GetWindowConfigurer(); + berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); berry::IWorkbenchWindow::Pointer window = configurer->GetWindow(); berry::IEditorPart::Pointer activeEditor; berry::IWorkbenchPage::Pointer currentPage = window->GetActivePage(); berry::IPerspectiveDescriptor::Pointer persp; berry::IAdaptable* input = nullptr; if (currentPage) { activeEditor = currentPage->GetActiveEditor(); persp = currentPage->GetPerspective(); input = currentPage->GetInput(); } if (editorHidden) { activeEditor = nullptr; } // Nothing to do if the editor hasn't changed if (activeEditor == lastActiveEditor.Lock() && currentPage == lastActivePage.Lock() && persp == lastPerspective.Lock() && input == lastInput) { return; } if (!lastActiveEditor.Expired()) { lastActiveEditor.Lock()->RemovePropertyListener(editorPropertyListener.data()); } lastActiveEditor = activeEditor; lastActivePage = currentPage; lastPerspective = persp; lastInput = input; if (activeEditor) { activeEditor->AddPropertyListener(editorPropertyListener.data()); } RecomputeTitle(); } void QmitkExtWorkbenchWindowAdvisor::PropertyChange(const berry::Object::Pointer& /*source*/, int propId) { if (propId == berry::IWorkbenchPartConstants::PROP_TITLE) { if (!lastActiveEditor.Expired()) { QString newTitle = lastActiveEditor.Lock()->GetPartName(); if (lastEditorTitle != newTitle) { RecomputeTitle(); } } } } void QmitkExtWorkbenchWindowAdvisor::SetPerspectiveExcludeList(const QList& v) { this->perspectiveExcludeList = v; } QList QmitkExtWorkbenchWindowAdvisor::GetPerspectiveExcludeList() { return this->perspectiveExcludeList; } void QmitkExtWorkbenchWindowAdvisor::SetViewExcludeList(const QList& v) { this->viewExcludeList = v; } QList QmitkExtWorkbenchWindowAdvisor::GetViewExcludeList() { return this->viewExcludeList; } void QmitkExtWorkbenchWindowAdvisor::PostWindowClose() { berry::IWorkbenchWindow::Pointer window = this->GetWindowConfigurer()->GetWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); QSettings settings(GetQSettingsFile(), QSettings::IniFormat); settings.setValue("ToolbarPosition", mainWindow->saveState()); } QString QmitkExtWorkbenchWindowAdvisor::GetQSettingsFile() const { QFileInfo settingsInfo = QmitkCommonExtPlugin::getContext()->getDataFile(QT_SETTINGS_FILENAME); return settingsInfo.canonicalFilePath(); } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h index f2414bdbd1..76ed29e22b 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtWorkbenchWindowAdvisor.h @@ -1,179 +1,181 @@ /*=================================================================== 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 QMITKEXTWORKBENCHWINDOWADVISOR_H_ #define QMITKEXTWORKBENCHWINDOWADVISOR_H_ #include #include #include #include #include #include #include #include class QAction; class QMenu; class MITK_QT_COMMON_EXT_EXPORT QmitkExtWorkbenchWindowAdvisor : public QObject, public berry::WorkbenchWindowAdvisor { Q_OBJECT public: QmitkExtWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer); ~QmitkExtWorkbenchWindowAdvisor() override; berry::SmartPointer CreateActionBarAdvisor( berry::SmartPointer configurer) override; QWidget* CreateEmptyWindowContents(QWidget* parent) override; void PostWindowCreate() override; void PreWindowOpen() override; void PostWindowOpen() override; void PostWindowClose() override; void ShowViewToolbar(bool show); void ShowPerspectiveToolbar(bool show); void ShowVersionInfo(bool show); void ShowMitkVersionInfo(bool show); void ShowViewMenuItem(bool show); void ShowNewWindowMenuItem(bool show); void ShowClosePerspectiveMenuItem(bool show); bool GetShowClosePerspectiveMenuItem(); void ShowMemoryIndicator(bool show); bool GetShowMemoryIndicator(); //TODO should be removed when product support is here void SetProductName(const QString& product); void SetWindowIcon(const QString& wndIcon); void SetPerspectiveExcludeList(const QList &v); QList GetPerspectiveExcludeList(); void SetViewExcludeList(const QList &v); QList GetViewExcludeList(); protected slots: virtual void onIntro(); virtual void onHelp(); virtual void onHelpOpenHelpPerspective(); virtual void onAbout(); private: /** * Hooks the listeners needed on the window * * @param configurer */ void HookTitleUpdateListeners(berry::IWorkbenchWindowConfigurer::Pointer configurer); QString ComputeTitle(); void RecomputeTitle(); QString GetQSettingsFile() const; /** * Updates the window title. Format will be: [pageInput -] * [currentPerspective -] [editorInput -] [workspaceLocation -] productName * @param editorHidden TODO */ void UpdateTitle(bool editorHidden); void PropertyChange(const berry::Object::Pointer& /*source*/, int propId); static QString QT_SETTINGS_FILENAME; QScopedPointer titlePartListener; QScopedPointer titlePerspectiveListener; QScopedPointer menuPerspectiveListener; QScopedPointer imageNavigatorPartListener; QScopedPointer viewNavigatorPartListener; QScopedPointer editorPropertyListener; friend struct berry::PropertyChangeIntAdapter; friend class PartListenerForTitle; friend class PerspectiveListenerForTitle; friend class PerspectiveListenerForMenu; friend class PartListenerForImageNavigator; friend class PartListenerForViewNavigator; berry::IEditorPart::WeakPtr lastActiveEditor; berry::IPerspectiveDescriptor::WeakPtr lastPerspective; berry::IWorkbenchPage::WeakPtr lastActivePage; QString lastEditorTitle; berry::IAdaptable* lastInput; berry::WorkbenchAdvisor* wbAdvisor; bool showViewToolbar; bool showPerspectiveToolbar; bool showVersionInfo; bool showMitkVersionInfo; bool showViewMenuItem; bool showNewWindowMenuItem; bool showClosePerspectiveMenuItem; bool viewNavigatorFound; bool showMemoryIndicator; QString productName; QString windowIcon; // enables DnD on the editor area QScopedPointer dropTargetListener; // stringlist for excluding perspectives from the perspective menu entry (e.g. Welcome Perspective) QList perspectiveExcludeList; // stringlist for excluding views from the menu entry QList viewExcludeList; // maps perspective ids to QAction objects QHash mapPerspIdToAction; // actions which will be enabled/disabled depending on the application state QList viewActions; QAction* fileSaveProjectAction; QAction* closeProjectAction; QAction* undoAction; QAction* redoAction; QAction* imageNavigatorAction; QAction* viewNavigatorAction; QAction* resetPerspAction; QAction* closePerspAction; QAction* openDicomEditorAction; + QAction* openStdMultiWidgetEditorAction; + QAction* openMxNMultiWidgetEditorAction; }; #endif /*QMITKEXTWORKBENCHWINDOWADVISOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp new file mode 100644 index 0000000000..293f5e1fad --- /dev/null +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp @@ -0,0 +1,82 @@ +/*=================================================================== + +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 "QmitkOpenMxNMultiWidgetEditorAction.h" + +#include "mitkCoreObjectFactory.h" + +#include +#include +#include +#include +#include +#include + +#include "internal/QmitkCommonExtPlugin.h" +#include + +class ctkPluginContext; + +QmitkOpenMxNMultiWidgetEditorAction::QmitkOpenMxNMultiWidgetEditorAction(berry::IWorkbenchWindow::Pointer window) + : QAction(nullptr) +{ + this->init(window); +} + +QmitkOpenMxNMultiWidgetEditorAction::QmitkOpenMxNMultiWidgetEditorAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window) + : QAction(nullptr) +{ + this->setIcon(icon); + + this->init(window); +} + +void QmitkOpenMxNMultiWidgetEditorAction::init(berry::IWorkbenchWindow::Pointer window) +{ + m_Window = window; + this->setParent(static_cast(m_Window->GetShell()->GetControl())); + this->setText("MxN Display"); + this->setToolTip("Open the mxn multi widget editor"); + + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + m_GeneralPreferencesNode = prefService->GetSystemPreferences()->Node("/General"); + + this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); +} + +void QmitkOpenMxNMultiWidgetEditorAction::Run() +{ + // check if there is an open perspective, if not open the default perspective + if (m_Window->GetActivePage().IsNull()) + { + QString defaultPerspId = m_Window->GetWorkbench()->GetPerspectiveRegistry()->GetDefaultPerspective(); + m_Window->GetWorkbench()->ShowPerspective(defaultPerspId, m_Window); + } + + ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); + ctkServiceReference serviceRef = context->getServiceReference(); + if (serviceRef) + { + mitk::IDataStorageService* dsService = context->getService(serviceRef); + if (dsService) + { + mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); + berry::IEditorInput::Pointer editorInput(new mitk::DataStorageEditorInput(dsRef)); + m_Window->GetActivePage()->OpenEditor(editorInput, "org.mitk.editors.mxnmultiwidget", true, berry::IWorkbenchPage::MATCH_ID); + } + } +} diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.h new file mode 100644 index 0000000000..2c159d761c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.h @@ -0,0 +1,56 @@ +/*=================================================================== + +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 QMITKOPENMXNMULTIWIDGETEDITORACTION_H +#define QMITKOPENMXNMULTIWIDGETEDITORACTION_H + +#ifdef __MINGW32__ +// We need to include winbase.h here in order to declare +// atomic intrinsics like InterlockedIncrement correctly. +// Otherwise they would be declared wrong within qatomic_windows.h . +#include +#endif + +#include +#include + +#include + +#include +#include + +class MITK_QT_COMMON_EXT_EXPORT QmitkOpenMxNMultiWidgetEditorAction : public QAction +{ + Q_OBJECT + +public: + + QmitkOpenMxNMultiWidgetEditorAction(berry::IWorkbenchWindow::Pointer window); + QmitkOpenMxNMultiWidgetEditorAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window); + +protected slots: + + void Run(); + +private: + + void init(berry::IWorkbenchWindow::Pointer window); + berry::IWorkbenchWindow::Pointer m_Window; + berry::IPreferences::WeakPtr m_GeneralPreferencesNode; + +}; + +#endif // QMITKOPENMXNMULTIWIDGETEDITORACTION_H diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp new file mode 100644 index 0000000000..459b8003d1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp @@ -0,0 +1,82 @@ +/*=================================================================== + +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 "QmitkOpenStdMultiWidgetEditorAction.h" + +#include "mitkCoreObjectFactory.h" + +#include +#include +#include +#include +#include +#include + +#include "internal/QmitkCommonExtPlugin.h" +#include + +class ctkPluginContext; + +QmitkOpenStdMultiWidgetEditorAction::QmitkOpenStdMultiWidgetEditorAction(berry::IWorkbenchWindow::Pointer window) + : QAction(nullptr) +{ + this->init(window); +} + +QmitkOpenStdMultiWidgetEditorAction::QmitkOpenStdMultiWidgetEditorAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window) + : QAction(nullptr) +{ + this->setIcon(icon); + + this->init(window); +} + +void QmitkOpenStdMultiWidgetEditorAction::init(berry::IWorkbenchWindow::Pointer window) +{ + m_Window = window; + this->setParent(static_cast(m_Window->GetShell()->GetControl())); + this->setText("Standard Display"); + this->setToolTip("Open the standard multi widget editor"); + + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + m_GeneralPreferencesNode = prefService->GetSystemPreferences()->Node("/General"); + + this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); +} + +void QmitkOpenStdMultiWidgetEditorAction::Run() +{ + // check if there is an open perspective, if not open the default perspective + if (m_Window->GetActivePage().IsNull()) + { + QString defaultPerspId = m_Window->GetWorkbench()->GetPerspectiveRegistry()->GetDefaultPerspective(); + m_Window->GetWorkbench()->ShowPerspective(defaultPerspId, m_Window); + } + + ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); + ctkServiceReference serviceRef = context->getServiceReference(); + if (serviceRef) + { + mitk::IDataStorageService* dsService = context->getService(serviceRef); + if (dsService) + { + mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); + berry::IEditorInput::Pointer editorInput(new mitk::DataStorageEditorInput(dsRef)); + m_Window->GetActivePage()->OpenEditor(editorInput, "org.mitk.editors.stdmultiwidget", true, berry::IWorkbenchPage::MATCH_ID); + } + } +} diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.h new file mode 100644 index 0000000000..ed0a4dbad8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.h @@ -0,0 +1,56 @@ +/*=================================================================== + +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 QMITKOPENSTDMULTIWIDGETEDITORACTION_H +#define QMITKOPENSTDMULTIWIDGETEDITORACTION_H + +#ifdef __MINGW32__ +// We need to inlclude winbase.h here in order to declare +// atomic intrinsics like InterlockedIncrement correctly. +// Otherwhise, they would be declared wrong within qatomic_windows.h . +#include +#endif + +#include +#include + +#include + +#include +#include + +class MITK_QT_COMMON_EXT_EXPORT QmitkOpenStdMultiWidgetEditorAction : public QAction +{ + Q_OBJECT + +public: + + QmitkOpenStdMultiWidgetEditorAction(berry::IWorkbenchWindow::Pointer window); + QmitkOpenStdMultiWidgetEditorAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window); + +protected slots: + + void Run(); + +private: + + void init(berry::IWorkbenchWindow::Pointer window); + berry::IWorkbenchWindow::Pointer m_Window; + berry::IPreferences::WeakPtr m_GeneralPreferencesNode; + +}; + +#endif // QMITKOPENSTDMULTIWIDGETEDITORACTION_H diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/CMakeLists.txt b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/CMakeLists.txt new file mode 100644 index 0000000000..311da29037 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_mxnmultiwidgeteditor) + +mitk_create_plugin( + EXPORT_DIRECTIVE MXNMULTIWIDGETEDITOR_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgets MitkRenderWindowManager +) diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake new file mode 100644 index 0000000000..fce4919a70 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/files.cmake @@ -0,0 +1,37 @@ +set(SRC_CPP_FILES + QmitkMxNMultiWidgetEditor.cpp + QmitkMultiWidgetDecorationManager.cpp +) + +set(INTERNAL_CPP_FILES + mitkPluginActivator.cpp + QmitkMxNMultiWidgetEditorPreferencePage.cpp +) + +set(UI_FILES + src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui +) + +set(MOC_H_FILES + src/QmitkMxNMultiWidgetEditor.h + + src/internal/mitkPluginActivator.h + src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h +) + +set(CACHED_RESOURCE_FILES + resources/MxNMultiWidgetEditor.svg + plugin.xml +) + +set(QRC_FILES + resources/QmitkMxNMultiWidgetEditor.qrc +) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/manifest_headers.cmake new file mode 100644 index 0000000000..3f743d0a72 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK MxN Multi Widget Editor") +set(Plugin-Version "1.0.0") +set(Plugin-Vendor "DKFZ, Division of Medical Image Computing") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/plugin.xml b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/plugin.xml new file mode 100644 index 0000000000..14dae7269c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/plugin.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/MxNMultiWidgetEditor.svg b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/MxNMultiWidgetEditor.svg new file mode 100644 index 0000000000..31d6ae02ac --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/MxNMultiWidgetEditor.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/QmitkMxNMultiWidgetEditor.qrc b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/QmitkMxNMultiWidgetEditor.qrc new file mode 100644 index 0000000000..655da7e3db --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/QmitkMxNMultiWidgetEditor.qrc @@ -0,0 +1,5 @@ + + + defaultWatermark.png + + diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/defaultWatermark.png b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/defaultWatermark.png new file mode 100644 index 0000000000..927adce68d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/resources/defaultWatermark.png differ diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp new file mode 100644 index 0000000000..6fe8154201 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.cpp @@ -0,0 +1,456 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkMultiWidgetDecorationManager.h" + +// org_mitk_gui_common +#include + +// mitk annotation +#include + +// vtk +#include + +// qt +#include + +QmitkMultiWidgetDecorationManager::QmitkMultiWidgetDecorationManager(QmitkMxNMultiWidget* mxnMultiWidget) + : m_MxNMultiWidget(mxnMultiWidget) + , m_LogoAnnotation(mitk::LogoAnnotation::New()) +{} + +void QmitkMultiWidgetDecorationManager::DecorationPreferencesChanged(const berry::IBerryPreferences* preferences) +{ + // Enable change of logo. If no DepartmentLogo was set explicitly, MITK Logo is used. + // Set new department logo by prefs->Set("DepartmentLogo", "PathToImage"); + + // If no logo was set for this plug-in specifically, walk the parent preference nodes + // and lookup a logo value there. + + // Disable the logo first, otherwise setting a new logo will have no effect due to how mitkManufacturerLogo works + ShowLogo(false); + SetupLogo(qPrintable(":/org.mitk.gui.qt.mxnmultiwidgeteditor/defaultWatermark.png")); + ShowLogo(true); + + const berry::IPreferences* currentNode = preferences; + while (currentNode) + { + bool logoFound = false; + foreach(const QString& key, currentNode->Keys()) + { + if (key == "DepartmentLogo") + { + ShowLogo(false); + QString departmentLogoLocation = currentNode->Get("DepartmentLogo", ""); + if (!departmentLogoLocation.isEmpty()) + { + SetupLogo(qPrintable(departmentLogoLocation)); + ShowLogo(true); + } + logoFound = true; + break; + } + } + + if (logoFound) + { + break; + } + currentNode = currentNode->Parent().GetPointer(); + } + + QmitkMultiWidgetDecorationManager::Colormap colormap = static_cast(preferences->GetInt("Render window widget colormap", 0)); + SetColormap(colormap); + + // show colored rectangle + ShowAllColoredRectangles(true); + + // show corner annotations + ShowAllCornerAnnotations(true); +} + +void QmitkMultiWidgetDecorationManager::ShowDecorations(bool show, const QStringList& decorations) +{ + if (nullptr != m_MxNMultiWidget) + { + return; + } + + if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_BORDER)) + { + ShowAllColoredRectangles(show); + } + if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_LOGO)) + { + ShowLogo(show); + } + if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_MENU)) + { + //m_MxNMultiWidget->ActivateAllRenderWindowMenus(show); + } + if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_BACKGROUND)) + { + ShowAllGradientBackgrounds(show); + } + if (decorations.isEmpty() || decorations.contains(mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION)) + { + ShowAllCornerAnnotations(show); + } +} + +bool QmitkMultiWidgetDecorationManager::IsDecorationVisible(const QString& decoration) const +{ + if (mitk::IRenderWindowPart::DECORATION_BORDER == decoration) + { + return AreAllColoredRectanglesVisible(); + } + else if (mitk::IRenderWindowPart::DECORATION_LOGO == decoration) + { + return IsLogoVisible(); + } + else if (mitk::IRenderWindowPart::DECORATION_MENU == decoration) + { + //return IsMenuWidgetEnabled(); + } + else if (mitk::IRenderWindowPart::DECORATION_BACKGROUND == decoration) + { + return AreAllGradientBackgroundsOn(); + } + else if (mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION == decoration) + { + return AreAllCornerAnnotationsVisible(); + } + + return false; +} + +QStringList QmitkMultiWidgetDecorationManager::GetDecorations() const +{ + QStringList decorations; + decorations << mitk::IRenderWindowPart::DECORATION_BORDER << mitk::IRenderWindowPart::DECORATION_LOGO << mitk::IRenderWindowPart::DECORATION_MENU + << mitk::IRenderWindowPart::DECORATION_BACKGROUND << mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION; + return decorations; +} + +////////////////////////////////////////////////////////////////////////// +// PRIVATE +////////////////////////////////////////////////////////////////////////// +void QmitkMultiWidgetDecorationManager::SetupLogo(const char* path) +{ + m_LogoAnnotation->SetOpacity(0.5); + mitk::Point2D offset; + offset.Fill(0.03); + m_LogoAnnotation->SetOffsetVector(offset); + m_LogoAnnotation->SetRelativeSize(0.25); + m_LogoAnnotation->SetCornerPosition(1); + vtkSmartPointer vtkLogo = GetVtkLogo(path); + + SetLogo(vtkLogo); +} + +vtkSmartPointer QmitkMultiWidgetDecorationManager::GetVtkLogo(const char* path) +{ + QImage* qimage = new QImage(path); + vtkSmartPointer qImageToVtk; + qImageToVtk = vtkSmartPointer::New(); + + qImageToVtk->SetQImage(qimage); + qImageToVtk->Update(); + vtkSmartPointer vtkLogo = qImageToVtk->GetOutput(); + return vtkLogo; +} + +void QmitkMultiWidgetDecorationManager::SetLogo(vtkSmartPointer vtkLogo) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetLastRenderWindowWidget(); + if (nullptr != renderWindowWidget && m_LogoAnnotation.IsNotNull()) + { + mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_LogoAnnotation.GetPointer(), renderWindowWidget->GetRenderWindow()->GetRenderer()); + m_LogoAnnotation->SetLogoImage(vtkLogo); + mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(renderWindowWidget->GetRenderWindow()->GetVtkRenderWindow()); + m_LogoAnnotation->Update(renderer); + renderWindowWidget->RequestUpdate(); + return; + } + + MITK_ERROR << "Logo can not be set for an unknown widget."; +} + +void QmitkMultiWidgetDecorationManager::ShowLogo(bool show) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetLastRenderWindowWidget(); + if (nullptr != renderWindowWidget) + { + m_LogoAnnotation->SetVisibility(show); + renderWindowWidget->RequestUpdate(); + return; + } + + MITK_ERROR << "Logo can not be shown for an unknown widget."; +} + +bool QmitkMultiWidgetDecorationManager::IsLogoVisible() const +{ + return m_LogoAnnotation->IsVisible(); +} + +void QmitkMultiWidgetDecorationManager::SetColormap(QmitkMultiWidgetDecorationManager::Colormap colormap) +{ + switch (colormap) + { + case Colormap::BlackAndWhite: + { + FillAllGradientBackgroundColorsWithBlack(); + float white[3] = { 1.0f, 1.0f, 1.0f }; + SetAllDecorationColors(white); + break; + } + } +} + +void QmitkMultiWidgetDecorationManager::SetDecorationColor(const QString& widgetID, const mitk::Color& color) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->SetDecorationColor(color); + return; + } + + MITK_ERROR << "Decoration color can not be set for an unknown widget."; +} + +void QmitkMultiWidgetDecorationManager::SetAllDecorationColors(const mitk::Color& color) +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + renderWindowWidget.second->SetDecorationColor(color); + } +} + +mitk::Color QmitkMultiWidgetDecorationManager::GetDecorationColor(const QString& widgetID) const +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->GetDecorationColor(); + } + + MITK_ERROR << "Decoration color can not be retrieved for an unknown widget. Returning black color!"; + float black[3] = { 0.0f, 0.0f, 0.0f }; + return mitk::Color(black); +} + +void QmitkMultiWidgetDecorationManager::ShowColoredRectangle(const QString& widgetID, bool show) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->ShowColoredRectangle(show); + return; + } + + MITK_ERROR << "Colored rectangle can not be set for an unknown widget."; +} + +void QmitkMultiWidgetDecorationManager::ShowAllColoredRectangles(bool show) +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + renderWindowWidget.second->ShowColoredRectangle(show); + } +} + +bool QmitkMultiWidgetDecorationManager::IsColoredRectangleVisible(const QString& widgetID) const +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->IsColoredRectangleVisible(); + } + + MITK_ERROR << "Colored rectangle visibility can not be retrieved for an unknown widget. Returning 'false'."; + return false; +} + +bool QmitkMultiWidgetDecorationManager::AreAllColoredRectanglesVisible() const +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + bool allTrue = true; + for (const auto& renderWindowWidget : renderWindowWidgets) + { + allTrue = allTrue && renderWindowWidget.second->IsColoredRectangleVisible(); + } + + return allTrue; +} + +void QmitkMultiWidgetDecorationManager::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower, const QString& widgetID) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->SetGradientBackgroundColors(upper, lower); + return; + } + + MITK_ERROR << "Background color gradient can not be set for an unknown widget."; +} + +void QmitkMultiWidgetDecorationManager::SetAllGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + renderWindowWidget.second->SetGradientBackgroundColors(upper, lower); + } +} + +void QmitkMultiWidgetDecorationManager::FillAllGradientBackgroundColorsWithBlack() +{ + float black[3] = { 0.0f, 0.0f, 0.0f }; + SetAllGradientBackgroundColors(black, black); +} + +void QmitkMultiWidgetDecorationManager::ShowGradientBackground(const QString& widgetID, bool show) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->ShowGradientBackground(show); + return; + } + + MITK_ERROR << "Background color gradient can not be shown for an unknown widget."; +} + +void QmitkMultiWidgetDecorationManager::ShowAllGradientBackgrounds(bool show) +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + renderWindowWidget.second->ShowGradientBackground(show); + } +} + +std::pair QmitkMultiWidgetDecorationManager::GetGradientBackgroundColors(const QString& widgetID) const +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->GetGradientBackgroundColors(); + } + + MITK_ERROR << "Background color gradient can not be retrieved for an unknown widget. Returning black color pair."; + float black[3] = { 0.0f, 0.0f, 0.0f }; + return std::make_pair(mitk::Color(black), mitk::Color(black)); +} + +bool QmitkMultiWidgetDecorationManager::IsGradientBackgroundOn(const QString& widgetID) const +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->IsGradientBackgroundOn(); + } + + MITK_ERROR << "Background color gradient flag can not be retrieved for an unknown widget. Returning 'false'."; + return false; +} + +bool QmitkMultiWidgetDecorationManager::AreAllGradientBackgroundsOn() const +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + bool allTrue = true; + for (const auto& renderWindowWidget : renderWindowWidgets) + { + allTrue = allTrue && renderWindowWidget.second->IsGradientBackgroundOn(); + } + + return allTrue; +} + +void QmitkMultiWidgetDecorationManager::SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->SetCornerAnnotationText(cornerAnnotation); + return; + } + + MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; +} + +std::string QmitkMultiWidgetDecorationManager::GetCornerAnnotationText(const QString& widgetID) const +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->GetCornerAnnotationText(); + } + + MITK_ERROR << "Corner annotation text can not be retrieved for an unknown widget."; + return ""; +} + +void QmitkMultiWidgetDecorationManager::ShowCornerAnnotation(const QString& widgetID, bool show) +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + renderWindowWidget->ShowCornerAnnotation(show); + return; + } + + MITK_ERROR << "Corner annotation can not be set for an unknown widget."; +} + +void QmitkMultiWidgetDecorationManager::ShowAllCornerAnnotations(bool show) +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + for (const auto& renderWindowWidget : renderWindowWidgets) + { + renderWindowWidget.second->ShowCornerAnnotation(show); + } +} + +bool QmitkMultiWidgetDecorationManager::IsCornerAnnotationVisible(const QString& widgetID) const +{ + std::shared_ptr renderWindowWidget = m_MxNMultiWidget->GetRenderWindowWidget(widgetID); + if (nullptr != renderWindowWidget) + { + return renderWindowWidget->IsCornerAnnotationVisible(); + } + + MITK_ERROR << "Corner annotation visibility can not be retrieved for an unknown widget. Returning 'false'."; + return false; +} + +bool QmitkMultiWidgetDecorationManager::AreAllCornerAnnotationsVisible() const +{ + QmitkMxNMultiWidget::RenderWindowWidgetMap renderWindowWidgets = m_MxNMultiWidget->GetRenderWindowWidgets(); + bool allTrue = true; + for (const auto& renderWindowWidget : renderWindowWidgets) + { + allTrue = allTrue && renderWindowWidget.second->IsCornerAnnotationVisible(); + } + + return allTrue; +} diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.h b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.h new file mode 100644 index 0000000000..8cc45cf9fa --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMultiWidgetDecorationManager.h @@ -0,0 +1,144 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKMXNMULTIWIDGETDECORATIONMANAGER_H +#define QMITKMXNMULTIWIDGETDECORATIONMANAGER_H + +// mxn multi widget editor +#include + +// mitk core +#include + +// mitk annotation +#include + +// mitk qtwidgets +#include + +// berry +#include + +// vtk +#include +#include + +// qt +#include +#include + +/** +* @brief +* +* +*/ +class MXNMULTIWIDGETEDITOR_EXPORT QmitkMultiWidgetDecorationManager +{ + +public: + + QmitkMultiWidgetDecorationManager(QmitkMxNMultiWidget* mxnMultiWidget); + + enum class Colormap + { + BlackAndWhite = 0 // black background, white decoration + }; + + void DecorationPreferencesChanged(const berry::IBerryPreferences* preferences); + + /** + * @brief Show or hide decorations like like colored borders or background, logos, menu widgets, logos and + * text annotations. + * + * \@par Show the decorations specified in decorations if true. Hide them, if not. + * \@par A list of decoration names. If empty, all supported decorations are affected. + */ + void ShowDecorations(bool show, const QStringList& decorations); + /** + * @brief Return if a specific decoration is visible. + * + * \return True, if the specified decoration is shown, false if not. + */ + bool IsDecorationVisible(const QString &decoration) const; + QStringList GetDecorations() const; + +private: + + void SetupLogo(const char* path); + vtkSmartPointer GetVtkLogo(const char* path); + void SetLogo(vtkSmartPointer vtkLogo); + void ShowLogo(bool show); + bool IsLogoVisible() const; + + void SetColormap(Colormap colormap); + + void SetDecorationColor(const QString& widgetID, const mitk::Color& color); + void SetAllDecorationColors(const mitk::Color& color); + mitk::Color GetDecorationColor(const QString& widgetID) const; + + void ShowColoredRectangle(const QString& widgetID, bool show); + void ShowAllColoredRectangles(bool show); + bool IsColoredRectangleVisible(const QString& widgetID) const; + bool AreAllColoredRectanglesVisible() const; + + /** + * @brief Set a background color gradient for a specific render window. + * + * If two different input colors are used, a gradient background is generated. + * + * @param upper The color of the gradient background. + * @param lower The color of the gradient background. + * @param widgetID The widget identifier. + */ + void SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower, const QString& widgetID); + /** + * @brief Set a background color gradient for all available render windows. + * + * If two different input colors are used, a gradient background is generated. + * + * @param upper The color of the gradient background. + * @param lower The color of the gradient background. + */ + void SetAllGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower); + void FillAllGradientBackgroundColorsWithBlack(); + void ShowGradientBackground(const QString& widgetID, bool show); + void ShowAllGradientBackgrounds(bool show); + /** + * @brief Return a render window (widget) specific background color gradient + * + * @param widgetID The widget identifier. + * + * @return A color gradient as a pair of colors. + * First entry: upper color value + * Second entry: lower color value + */ + std::pair GetGradientBackgroundColors(const QString& widgetID) const; + bool IsGradientBackgroundOn(const QString& widgetID) const; + bool AreAllGradientBackgroundsOn() const; + + void SetCornerAnnotationText(const QString& widgetID, const std::string& cornerAnnotation); + std::string GetCornerAnnotationText(const QString& widgetID) const; + void ShowCornerAnnotation(const QString& widgetID, bool show); + void ShowAllCornerAnnotations(bool show); + bool IsCornerAnnotationVisible(const QString& widgetID) const; + bool AreAllCornerAnnotationsVisible() const; + + QmitkMxNMultiWidget* m_MxNMultiWidget; + mitk::LogoAnnotation::Pointer m_LogoAnnotation; + +}; + +#endif // QMITKMXNMULTIWIDGETDECORATIONMANAGER_H diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp new file mode 100644 index 0000000000..bf802f1d33 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp @@ -0,0 +1,248 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkMxNMultiWidgetEditor.h" + +#include +#include +#include +#include +#include + +// mxn multi widget editor plugin +#include "QmitkMultiWidgetDecorationManager.h" + +// mitk qt widgets module +#include +#include +#include + +const QString QmitkMxNMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.mxnmultiwidget"; + +class QmitkMxNMultiWidgetEditor::Impl final +{ + +public: + + Impl(); + ~Impl() = default; + + QmitkMxNMultiWidget* m_MxNMultiWidget; + QmitkInteractionSchemeToolBar* m_InteractionSchemeToolBar; + QmitkMultiWidgetConfigurationToolBar* m_ConfigurationToolBar; + + std::unique_ptr m_MultiWidgetDecorationManager; +}; + +QmitkMxNMultiWidgetEditor::Impl::Impl() + : m_MxNMultiWidget(nullptr) + , m_InteractionSchemeToolBar(nullptr) + , m_ConfigurationToolBar(nullptr) +{ + // nothing here +} + +////////////////////////////////////////////////////////////////////////// +// QmitkMxNMultiWidgetEditor +////////////////////////////////////////////////////////////////////////// +QmitkMxNMultiWidgetEditor::QmitkMxNMultiWidgetEditor() + : m_Impl(new Impl()) +{} + +QmitkMxNMultiWidgetEditor::~QmitkMxNMultiWidgetEditor() +{ + GetSite()->GetPage()->RemovePartListener(this); +} + +QmitkRenderWindow* QmitkMxNMultiWidgetEditor::GetActiveQmitkRenderWindow() const +{ + if (nullptr != m_Impl->m_MxNMultiWidget) + { + auto activeRenderWindowWidget = m_Impl->m_MxNMultiWidget->GetActiveRenderWindowWidget(); + if (nullptr != activeRenderWindowWidget) + { + return activeRenderWindowWidget->GetRenderWindow(); + } + } + + return nullptr; +} + +QHash QmitkMxNMultiWidgetEditor::GetQmitkRenderWindows() const +{ + QHash result; + if (nullptr == m_Impl->m_MxNMultiWidget) + { + return result; + } + + result = m_Impl->m_MxNMultiWidget->GetRenderWindows(); + return result; +} + +QmitkRenderWindow* QmitkMxNMultiWidgetEditor::GetQmitkRenderWindow(const QString& id) const +{ + if (nullptr == m_Impl->m_MxNMultiWidget) + { + return nullptr; + } + + return m_Impl->m_MxNMultiWidget->GetRenderWindow(id); +} + +mitk::Point3D QmitkMxNMultiWidgetEditor::GetSelectedPosition(const QString& id) const +{ + if (nullptr == m_Impl->m_MxNMultiWidget) + { + return mitk::Point3D(); + } + + return m_Impl->m_MxNMultiWidget->GetSelectedPosition(id); +} + +void QmitkMxNMultiWidgetEditor::SetSelectedPosition(const mitk::Point3D& pos, const QString& id) +{ + if (nullptr != m_Impl->m_MxNMultiWidget) + { + m_Impl->m_MxNMultiWidget->SetSelectedPosition(id, pos); + } +} + +void QmitkMxNMultiWidgetEditor::EnableDecorations(bool enable, const QStringList& decorations) +{ + m_Impl->m_MultiWidgetDecorationManager->ShowDecorations(enable, decorations); +} + +bool QmitkMxNMultiWidgetEditor::IsDecorationEnabled(const QString& decoration) const +{ + return m_Impl->m_MultiWidgetDecorationManager->IsDecorationVisible(decoration); +} + +QStringList QmitkMxNMultiWidgetEditor::GetDecorations() const +{ + return m_Impl->m_MultiWidgetDecorationManager->GetDecorations(); +} + +berry::IPartListener::Events::Types QmitkMxNMultiWidgetEditor::GetPartEventTypes() const +{ + return Events::CLOSED | Events::OPENED; +} + +void QmitkMxNMultiWidgetEditor::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) +{ + if (partRef->GetId() == QmitkMxNMultiWidgetEditor::EDITOR_ID) + { + m_Impl->m_MxNMultiWidget->ActivateAllCrosshairs(true); + } +} + +void QmitkMxNMultiWidgetEditor::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) +{ + if (partRef->GetId() == QmitkMxNMultiWidgetEditor::EDITOR_ID) + { + m_Impl->m_MxNMultiWidget->ActivateAllCrosshairs(false); + } +} + +QmitkMxNMultiWidget* QmitkMxNMultiWidgetEditor::GetMxNMultiWidget() +{ + return m_Impl->m_MxNMultiWidget; +} + +void QmitkMxNMultiWidgetEditor::OnLayoutSet(int row, int column) +{ + m_Impl->m_MxNMultiWidget->ResetLayout(row, column); + m_Impl->m_MxNMultiWidget->ActivateAllCrosshairs(true); + FirePropertyChange(berry::IWorkbenchPartConstants::PROP_INPUT); +} + +void QmitkMxNMultiWidgetEditor::OnSynchronize(bool synchronized) +{ + m_Impl->m_MxNMultiWidget->Synchronize(synchronized); +} + +////////////////////////////////////////////////////////////////////////// +// PRIVATE +////////////////////////////////////////////////////////////////////////// +void QmitkMxNMultiWidgetEditor::SetFocus() +{ + if (nullptr != m_Impl->m_MxNMultiWidget) + { + m_Impl->m_MxNMultiWidget->setFocus(); + } +} + +void QmitkMxNMultiWidgetEditor::CreateQtPartControl(QWidget* parent) +{ + if (nullptr == m_Impl->m_MxNMultiWidget) + { + QHBoxLayout* layout = new QHBoxLayout(parent); + layout->setContentsMargins(0, 0, 0, 0); + + berry::IBerryPreferences* preferences = dynamic_cast(GetPreferences().GetPointer()); + mitk::BaseRenderer::RenderingMode::Type renderingMode = static_cast(preferences->GetInt("Rendering Mode", 0)); + + m_Impl->m_MxNMultiWidget = new QmitkMxNMultiWidget(parent, 0, 0, renderingMode); + + // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves + if (nullptr == m_Impl->m_InteractionSchemeToolBar) + { + m_Impl->m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); + layout->addWidget(m_Impl->m_InteractionSchemeToolBar); + } + m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(m_Impl->m_MxNMultiWidget->GetInteractionEventHandler()); + + // add center widget: the mxn multi widget + layout->addWidget(m_Impl->m_MxNMultiWidget); + + m_Impl->m_MxNMultiWidget->SetDataStorage(GetDataStorage()); + m_Impl->m_MxNMultiWidget->InitializeRenderWindowWidgets(); + + // create right toolbar: configuration toolbar to change the render window widget layout + if (nullptr == m_Impl->m_ConfigurationToolBar) + { + m_Impl->m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(); + layout->addWidget(m_Impl->m_ConfigurationToolBar); + } + + connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::LayoutSet, this, &QmitkMxNMultiWidgetEditor::OnLayoutSet); + connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::Synchronized, this, &QmitkMxNMultiWidgetEditor::OnSynchronize); + + m_Impl->m_MultiWidgetDecorationManager = std::make_unique(m_Impl->m_MxNMultiWidget); + + GetSite()->GetPage()->AddPartListener(this); + + OnPreferencesChanged(preferences); + } +} + +void QmitkMxNMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) +{ + if (m_Impl->m_MxNMultiWidget->GetRenderWindowWidgets().empty()) + { + return; + } + + // update decoration preferences + m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); + + // zooming and panning preferences + bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); + mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); + + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h new file mode 100644 index 0000000000..ea9db18593 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.h @@ -0,0 +1,118 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKMXNMULTIWIDGETEDITOR_H +#define QMITKMXNMULTIWIDGETEDITOR_H + +#include +#include + +#include + +// berry +#include + +#include + +class QmitkMxNMultiWidget; + +class MXNMULTIWIDGETEDITOR_EXPORT QmitkMxNMultiWidgetEditor final : public QmitkAbstractRenderEditor, public berry::IPartListener +{ + Q_OBJECT + +public: + + berryObjectMacro(QmitkMxNMultiWidgetEditor) + + static const QString EDITOR_ID; + + QmitkMxNMultiWidgetEditor(); + virtual ~QmitkMxNMultiWidgetEditor(); + + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QmitkRenderWindow* GetActiveQmitkRenderWindow() const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QHash GetQmitkRenderWindows() const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QmitkRenderWindow* GetQmitkRenderWindow(const QString& id) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual mitk::Point3D GetSelectedPosition(const QString& id = QString()) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual void SetSelectedPosition(const mitk::Point3D& pos, const QString& id = QString()) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual void EnableDecorations(bool enable, const QStringList& decorations = QStringList()) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual bool IsDecorationEnabled(const QString& decoration) const override; + /** + * @brief Overridden from QmitkAbstractRenderEditor : IRenderWindowPart + */ + virtual QStringList GetDecorations() const override; + /** + * @brief Overridden from berry::IPartListener + */ + berry::IPartListener::Events::Types GetPartEventTypes() const override; + /** + * @brief Overridden from berry::IPartListener + */ + void PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) override; + /** + * @brief Overridden from berry::IPartListener + */ + void PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) override; + + /** + * @brief Return the current MxN multi widget of this editor. + */ + QmitkMxNMultiWidget* GetMxNMultiWidget(); + +private Q_SLOTS: + + void OnLayoutSet(int row, int column); + void OnSynchronize(bool synchronized); + +private: + /** + * @brief Overridden from QmitkAbstractRenderEditor + */ + virtual void SetFocus() override; + /** + * @brief Overridden from QmitkAbstractRenderEditor + */ + virtual void CreateQtPartControl(QWidget* parent) override; + /** + * @brief Overridden from QmitkAbstractRenderEditor + */ + virtual void OnPreferencesChanged(const berry::IBerryPreferences* preferences) override; + + class Impl; + const std::unique_ptr m_Impl; +}; + +#endif // QMITKMXNMULTIWIDGETEDITOR_H diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp new file mode 100644 index 0000000000..3d52dd803c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp @@ -0,0 +1,128 @@ +/*=================================================================== + +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 "QmitkMxNMultiWidgetEditorPreferencePage.h" +#include + +// berry framework +#include +#include + +QmitkMxNMultiWidgetEditorPreferencePage::QmitkMxNMultiWidgetEditorPreferencePage() + : m_Preferences(nullptr) +{ + // nothing here +} + +QmitkMxNMultiWidgetEditorPreferencePage::~QmitkMxNMultiWidgetEditorPreferencePage() +{ + //nothing here +} + +void QmitkMxNMultiWidgetEditorPreferencePage::Init(berry::IWorkbench::Pointer) +{ + // nothing here +} + +void QmitkMxNMultiWidgetEditorPreferencePage::CreateQtControl(QWidget* parent) +{ + m_MainControl = new QWidget(parent); + + m_Ui.setupUi(m_MainControl); + + berry::IPreferencesService* preferenceService = berry::Platform::GetPreferencesService(); + Q_ASSERT(preferenceService); + m_Preferences = preferenceService->GetSystemPreferences()->Node(QmitkMxNMultiWidgetEditor::EDITOR_ID); + + connect(m_Ui.m_RenderingModeComboBox, SIGNAL(activated(int)), SLOT(ChangeRenderingMode(int))); + connect(m_Ui.m_ColormapComboBox, SIGNAL(activated(int)), SLOT(ChangeColormap(int))); + connect(m_Ui.m_ResetButton, SIGNAL(clicked()), SLOT(ResetPreferencesAndGUI())); + + Update(); +} + +QWidget* QmitkMxNMultiWidgetEditorPreferencePage::GetQtControl() const +{ + return m_MainControl; +} + +bool QmitkMxNMultiWidgetEditorPreferencePage::PerformOk() +{ + m_Preferences->PutBool("Use constrained zooming and panning", m_Ui.m_EnableFlexibleZooming->isChecked()); + m_Preferences->PutBool("Show level/window widget", m_Ui.m_ShowLevelWindowWidget->isChecked()); + m_Preferences->PutBool("PACS like mouse interaction", m_Ui.m_PACSLikeMouseMode->isChecked()); + + m_Preferences->PutInt("Rendering Mode", m_Ui.m_RenderingModeComboBox->currentIndex()); + + m_Preferences->PutInt("Render window widget colormap", m_Ui.m_ColormapComboBox->currentIndex()); + m_Preferences->PutBool("Render window individual decorations", m_Ui.m_IndividualDecorations->isChecked()); + + m_Preferences->PutInt("crosshair gap size", m_Ui.m_CrosshairGapSize->value()); + + return true; +} + +void QmitkMxNMultiWidgetEditorPreferencePage::PerformCancel() +{ + // nothing here +} + +void QmitkMxNMultiWidgetEditorPreferencePage::Update() +{ + m_Ui.m_EnableFlexibleZooming->setChecked(m_Preferences->GetBool("Use constrained zooming and panning", true)); + m_Ui.m_ShowLevelWindowWidget->setChecked(m_Preferences->GetBool("Show level/window widget", true)); + m_Ui.m_PACSLikeMouseMode->setChecked(m_Preferences->GetBool("PACS like mouse interaction", false)); + + int renderingMode = m_Preferences->GetInt("Rendering Mode", 0); + m_Ui.m_RenderingModeComboBox->setCurrentIndex(renderingMode); + + int colormap = m_Preferences->GetInt("Render window widget colormap", 0); + m_Ui.m_ColormapComboBox->setCurrentIndex(colormap); + + m_Ui.m_IndividualDecorations->setChecked(m_Preferences->GetBool("Render window individual decorations", false)); + + m_Ui.m_CrosshairGapSize->setValue(m_Preferences->GetInt("crosshair gap size", 32)); +} + +void QmitkMxNMultiWidgetEditorPreferencePage::ResetPreferencesAndGUI() +{ + m_Preferences->Clear(); + Update(); +} + +void QmitkMxNMultiWidgetEditorPreferencePage::ChangeRenderingMode(int i) +{ + if (0 == i) + { + m_CurrentRenderingMode = "Standard"; + } + else if (1 == i) + { + m_CurrentRenderingMode = "Multisampling"; + } + else if (2 == i) + { + m_CurrentRenderingMode = "DepthPeeling"; + } +} + +void QmitkMxNMultiWidgetEditorPreferencePage::ChangeColormap(int i) +{ + if (0 == i) + { + m_CurrentColormap = "Black and white"; + } +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h new file mode 100644 index 0000000000..3dfa1e002b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h @@ -0,0 +1,80 @@ +/*=================================================================== + +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 QMITKMXNMULTIWIDGETEDITORPREFERENCEPAGE_H +#define QMITKMXNMULTIWIDGETEDITORPREFERENCEPAGE_H + +#include "ui_QmitkMxNMultiWidgetEditorPreferencePage.h" + +#include +#include +#include +#include +#include + +class QmitkMxNMultiWidgetEditorPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + + QmitkMxNMultiWidgetEditorPreferencePage(); + ~QmitkMxNMultiWidgetEditorPreferencePage(); + + void Init(berry::IWorkbench::Pointer) override; + void CreateQtControl(QWidget* parent) override; + QWidget* GetQtControl() const override; + + bool PerformOk() override; + void PerformCancel() override; + void Update() override; + +public slots: + /** + * @brief ResetColors set default colors and refresh the GUI. + */ + void ResetPreferencesAndGUI(); + + /** + * @brief ChangeRenderingMode slot to chose the rendering mode via QComboBox. + * @param i index of the box. + */ + void ChangeRenderingMode(int i); + + void ChangeColormap(int i); + +protected: + /** + * @brief m_CurrentRenderingMode String for the rendering mode. + */ + std::string m_CurrentRenderingMode; + + std::string m_CurrentColormap; + + /** + * @brief m_Preferences the berry preferences. + */ + berry::IPreferences::Pointer m_Preferences; + +private: + + Ui::QmitkMxNMultiWidgetEditorPreferencePage m_Ui; + QWidget* m_MainControl; + +}; + +#endif // QMITKMXNMULTIWIDGETEDITORPREFERENCEPAGE_H diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui new file mode 100644 index 0000000000..0bf3df7077 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui @@ -0,0 +1,163 @@ + + + QmitkMxNMultiWidgetEditorPreferencePage + + + + 0 + 0 + 520 + 320 + + + + External Programs + + + + + + <html><head/><body><p>If activated, zooming and panning is limited to a certain space around each image.</p></body></html> + + + Qt::LeftToRight + + + Use constraint zooming and panning + + + true + + + + + + + Qt::LeftToRight + + + Show level/window widget + + + true + + + + + + + Qt::LeftToRight + + + Use PACS like mouse interaction (select left mouse button action) + + + + + + + Qt::Horizontal + + + + + + + Rendering Mode* + + + + + + + + Standard Rendering + + + + + Enable Multisampling (Antialiasing) + + + + + Enable Depth Peeling + + + + + + + + * Changes require restart of MITK. + Depth Peeling is only supported by Windows. + For other OS, use Standard Rendering and enable + the property 'Depth Sorting' in the property list of the surface data node. + + + + + + + Qt::Horizontal + + + + + + + Colormap + + + + + + + + Black and white + + + + + + + + + 0 + 0 + + + + Allow render window individual decorations + + + + + + + <html><head/><body><p>The gap in the middle of the crosshair in pixels.</p></body></html> + + + Crosshair gap size + + + + + + + 32 + + + + + + + Reset preferences + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/mitkPluginActivator.cpp new file mode 100644 index 0000000000..f4e79f4657 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/mitkPluginActivator.cpp @@ -0,0 +1,45 @@ +/*=================================================================== + +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 "mitkPluginActivator.h" + +#include +#include "QmitkMxNMultiWidgetEditorPreferencePage.h" + +namespace mitk +{ + ctkPluginContext* MxNMultiWidgetActivator::m_Context = nullptr; + + void MxNMultiWidgetActivator::start(ctkPluginContext* context) + { + m_Context = context; + + BERRY_REGISTER_EXTENSION_CLASS(QmitkMxNMultiWidgetEditor, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkMxNMultiWidgetEditorPreferencePage, context) + } + + void MxNMultiWidgetActivator::stop(ctkPluginContext* context) + { + Q_UNUSED(context) + + m_Context = nullptr; + } + + ctkPluginContext* MxNMultiWidgetActivator::GetContext() + { + return m_Context; + } +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/mitkPluginActivator.h new file mode 100644 index 0000000000..57910bd4f5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/mitkPluginActivator.h @@ -0,0 +1,43 @@ +/*=================================================================== + +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 MITKPLUGINACTIVATOR_H +#define MITKPLUGINACTIVATOR_H + +#include + +namespace mitk +{ + class MxNMultiWidgetActivator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_mxnmultiwidgeteditor") + Q_INTERFACES(ctkPluginActivator) + + public: + + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + + static ctkPluginContext* GetContext(); + + private: + + static ctkPluginContext* m_Context; + + }; +} +#endif // MITKPLUGINACTIVATOR_H diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.renderwindowmanager/manifest_headers.cmake index 047fb72062..72676e48b5 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Render window layer manager") set(Plugin-Version "0.1") set(Plugin-Vendor "DKFZ") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.application org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp index 99ef6fcaf9..d5cdc23bca 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp @@ -1,156 +1,125 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager plugin #include "QmitkRenderWindowManagerView.h" -// blueberry -#include -#include - // mitk core #include #include - -// org.mitk.gui.qt.common -#include +#include const std::string QmitkRenderWindowManagerView::VIEW_ID = "org.mitk.views.renderwindowmanager"; +void QmitkRenderWindowManagerView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +{ + if (m_RenderWindowPart != renderWindowPart) + { + m_RenderWindowPart = renderWindowPart; + SetControlledRenderer(); + } +} + +void QmitkRenderWindowManagerView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) +{ + if (m_RenderWindowPart == renderWindowPart) + { + m_RenderWindowPart = nullptr; + SetControlledRenderer(); + } +} + +void QmitkRenderWindowManagerView::RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) +{ + if (m_RenderWindowPart == renderWindowPart) + { + SetControlledRenderer(); + } +} + void QmitkRenderWindowManagerView::SetFocus() { // nothing here } void QmitkRenderWindowManagerView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; // create GUI widgets m_Controls.setupUi(parent); - // add custom render window manager UI widget to the 'renderWindowManagerTab' - m_RenderWindowManipulatorWidget = new QmitkRenderWindowManipulatorWidget(GetDataStorage(), parent); - m_RenderWindowManipulatorWidget->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); - m_Controls.verticalLayout->addWidget(m_RenderWindowManipulatorWidget); + // add custom render window manager UI widget to the 'renderWindowManagerTab' + m_RenderWindowInspector = new QmitkRenderWindowDataStorageInspector(parent); + m_RenderWindowInspector->SetDataStorage(GetDataStorage()); + m_RenderWindowInspector->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); + m_Controls.verticalLayout->addWidget(m_RenderWindowInspector); + + // data node context menu and menu actions + m_InspectorView = m_RenderWindowInspector->GetView(); + m_DataNodeContextMenu = new QmitkDataNodeContextMenu(GetSite(), m_InspectorView); + m_DataNodeContextMenu->SetDataStorage(GetDataStorage()); + //m_DataNodeContextMenu->SetSurfaceDecimation(m_SurfaceDecimation); + + // connect objects + connect(m_Controls.comboBoxRenderWindowSelection, static_cast(&QComboBox::currentIndexChanged), this, &QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged); + connect(m_InspectorView, &QAbstractItemView::customContextMenuRequested, m_DataNodeContextMenu, &QmitkDataNodeContextMenu::OnContextMenuRequested); + + m_RenderWindowPart = GetRenderWindowPart(); + // also sets the controlled renderer SetControlledRenderer(); - - for (const auto& renderer : m_ControlledRenderer) - { - m_Controls.comboBoxRenderWindowSelection->addItem(renderer->GetName()); - } - - SetUpConnections(); - - OnRenderWindowSelectionChanged(m_Controls.comboBoxRenderWindowSelection->itemText(0)); } -void QmitkRenderWindowManagerView::SetUpConnections() +void QmitkRenderWindowManagerView::SetControlledRenderer() { - connect(m_Controls.comboBoxRenderWindowSelection, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnRenderWindowSelectionChanged(const QString&))); - connect(m_RenderWindowManipulatorWidget, SIGNAL(AddLayerButtonClicked()), this, SLOT(OnAddLayerButtonClicked())); - - m_ModelViewSelectionConnector = std::make_unique(); - try + QHash renderWindows; + if (m_RenderWindowPart != nullptr) { - m_ModelViewSelectionConnector->SetView(m_RenderWindowManipulatorWidget->GetLayerStackTableView()); + renderWindows = m_RenderWindowPart->GetQmitkRenderWindows(); } - catch (mitk::Exception& e) - { - mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; - } - m_SelectionServiceConnector = std::make_unique(); -} -void QmitkRenderWindowManagerView::SetControlledRenderer() -{ - const mitk::RenderingManager::RenderWindowVector allRegisteredRenderWindows = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); + mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer; + QStringList rendererNames; + m_Controls.comboBoxRenderWindowSelection->clear(); mitk::BaseRenderer* baseRenderer = nullptr; - for (const auto &renderWindow : allRegisteredRenderWindows) + for (const auto& renderWindow : renderWindows.values()) { - baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); + baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow()); if (nullptr != baseRenderer) { - m_ControlledRenderer.push_back(baseRenderer); + controlledRenderer.push_back(baseRenderer); + rendererNames.append(baseRenderer->GetName()); } } - m_RenderWindowManipulatorWidget->SetControlledRenderer(m_ControlledRenderer); -} - -void QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged(const QString &renderWindowId) -{ - m_RenderWindowManipulatorWidget->SetActiveRenderWindow(renderWindowId); + m_RenderWindowInspector->SetControlledRenderer(controlledRenderer); + rendererNames.sort(); + m_Controls.comboBoxRenderWindowSelection->addItems(rendererNames); } -void QmitkRenderWindowManagerView::OnAddLayerButtonClicked() +void QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged(const QString& renderWindowId) { - QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(m_Parent, "Select nodes to add to the render window", ""); - dialog->SetDataStorage(GetDataStorage()); - dialog->SetSelectOnlyVisibleNodes(true); - dialog->SetSelectionMode(QAbstractItemView::MultiSelection); - - if (QDialog::Accepted == dialog->exec()) + m_RenderWindowInspector->SetActiveRenderWindow(renderWindowId); + mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(renderWindowId.toStdString()); + if (nullptr != selectedRenderer) { - auto nodes = dialog->GetSelectedNodes(); - for (mitk::DataNode* dataNode : nodes) - { - if (nullptr != dataNode) - { - m_RenderWindowManipulatorWidget->AddLayer(dataNode); - - // get child nodes of the current node - mitk::DataStorage::SetOfObjects::ConstPointer derivedNodes = GetDataStorage()->GetDerivations(dataNode, nullptr, false); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = derivedNodes->Begin(); it != derivedNodes->End(); ++it) - { - m_RenderWindowManipulatorWidget->AddLayer(it->Value()); - } - } - } + m_DataNodeContextMenu->SetBaseRenderer(selectedRenderer); } - - delete dialog; } -void QmitkRenderWindowManagerView::SetSelectionProvider() +QItemSelectionModel* QmitkRenderWindowManagerView::GetDataNodeSelectionModel() const { - m_SelectionProvider = QmitkDataNodeSelectionProvider::Pointer(new QmitkDataNodeSelectionProvider); - m_SelectionProvider->SetItemSelectionModel(m_RenderWindowManipulatorWidget->GetLayerStackTableView()->selectionModel()); - GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(m_SelectionProvider)); - - // This function is called during the creation of the GUI. It is overridden in this class to create a custom selection provider. - // This view is used as a selection provider (not used as a selection listener) - m_SelectionServiceConnector->SetAsSelectionProvider(m_SelectionProvider.GetPointer()); - connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); -} - -void QmitkRenderWindowManagerView::NodeAdded(const mitk::DataNode* node) -{ - bool global = false; - node->GetBoolProperty("globalObject_RWM", global); - if (global) - { - // initially insert new point set node into the node list of all render windows - // the node object of a new point set won't be visible due to its "helper object" property set to true - m_RenderWindowManipulatorWidget->AddLayerToAllRenderer(const_cast(node)); - } - else - { - // initially set new node as invisible in all render windows - // this way, each single renderer overwrites the common renderer and the node is invisible - // until it is inserted into the node list of a render windows - m_RenderWindowManipulatorWidget->HideDataNodeInAllRenderer(node); - } + return m_InspectorView->selectionModel(); } diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h index 3d3968f752..762704b976 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h @@ -1,93 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWMANAGERVIEW_H #define QMITKRENDERWINDOWMANAGERVIEW_H // render window manager plugin #include "ui_QmitkRenderWindowManagerControls.h" // render window manager UI module -#include +#include -// blueberry -#include +// mitk gui qt application +#include + +// mitk gui common plugin +#include // mitk gui qt common plugin #include -#include "QmitkModelViewSelectionConnector.h" -#include "QmitkSelectionServiceConnector.h" /** * @brief RenderWindowManager */ -class QmitkRenderWindowManagerView : public QmitkAbstractView +class QmitkRenderWindowManagerView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; + virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; + virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; + virtual void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) override; + protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: /** * @brief Called when the user changes the render window selection in the combo box. * * @param renderWindowId The text inside the combo box. */ - void OnRenderWindowSelectionChanged(const QString &renderWindowId); - /** - * @brief Called when the 'AddLayer'-button of he render window manipulator widget has been pushed. - */ - void OnAddLayerButtonClicked(); + void OnRenderWindowSelectionChanged(const QString& renderWindowId); private: - void SetUpConnections(); void SetControlledRenderer(); - /** - * @brief see QmitkAbstractView - */ - void SetSelectionProvider() override; - /** - * @brief Reacts to a node that has been added to the data storage. - * 1. Insert new node into the node list of all render windows, if it is an "globalObject_RWM"-node. - * or else - * 2. Set data node invisible in all render windows, as soon as the node is added to the data storage. - */ - void NodeAdded(const mitk::DataNode* node) override; - - // the Qt parent of our GUI QWidget* m_Parent; Ui::QmitkRenderWindowManagerControls m_Controls; - QmitkRenderWindowManipulatorWidget* m_RenderWindowManipulatorWidget; - std::unique_ptr m_ModelViewSelectionConnector; - std::unique_ptr m_SelectionServiceConnector; - QmitkDataNodeSelectionProvider::Pointer m_SelectionProvider; + mitk::IRenderWindowPart* m_RenderWindowPart; + + QmitkRenderWindowDataStorageInspector* m_RenderWindowInspector; + QAbstractItemView* m_InspectorView; + QmitkDataNodeContextMenu* m_DataNodeContextMenu; - RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; + virtual QItemSelectionModel* GetDataNodeSelectionModel() const override; }; #endif // QMITKRENDERWINDOWMANAGERVIEW_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp index dafd7c2a72..43699e88fd 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp @@ -1,35 +1,30 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkAbstractSemanticRelationsAction.h" QmitkAbstractSemanticRelationsAction::QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QmitkAbstractDataNodeAction(workbenchPartSite) { m_SemanticRelationsIntegration = std::make_unique(); } QmitkAbstractSemanticRelationsAction::QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite* workbenchPartSite) : QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { // nothing here } - -QmitkAbstractSemanticRelationsAction::~QmitkAbstractSemanticRelationsAction() -{ - // nothing here -} diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h index eb2c57cdc4..0cef975cb7 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h @@ -1,41 +1,39 @@ /*=================================================================== 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 QMITKABSTRACTSEMANTICRELATIONSACTION_H #define QMITKABSTRACTSEMANTICRELATIONSACTION_H // mitk gui qt application plugin #include // semantic relations module #include class QmitkAbstractSemanticRelationsAction : public QmitkAbstractDataNodeAction { public: QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite* workbenchPartSite); - virtual ~QmitkAbstractSemanticRelationsAction() override; - protected: std::unique_ptr m_SemanticRelationsIntegration; }; #endif // QMITKABSTRACTSEMANTICRELATIONSACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp index 6e64071913..b38737f62b 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp @@ -1,77 +1,77 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkSemanticRelationsContextMenu.h" QmitkSemanticRelationsContextMenu::QmitkSemanticRelationsContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent) : QMenu(parent) , m_Parent(parent) , m_WorkbenchPartSite(workbenchPartSite) { InitDefaultActions(); } QmitkSemanticRelationsContextMenu::~QmitkSemanticRelationsContextMenu() { // nothing here } void QmitkSemanticRelationsContextMenu::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage - also for all actions m_DataStorage = dataStorage; m_ControlPointAction->SetDataStorage(m_DataStorage.Lock()); m_InformationTypeAction->SetDataStorage(m_DataStorage.Lock()); m_RemoveFromSemanticRelationsAction->SetDataStorage(m_DataStorage.Lock()); m_UnlinkFromLesionAction->SetDataStorage(m_DataStorage.Lock()); } } -void QmitkSemanticRelationsContextMenu::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) +void QmitkSemanticRelationsContextMenu::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { if (m_ControlledRenderer != controlledRenderer) { // set the new set of controlled renderer m_ControlledRenderer = controlledRenderer; m_OpenInAction->SetControlledRenderer(m_ControlledRenderer); } } void QmitkSemanticRelationsContextMenu::OnContextMenuRequested(const QPoint& /*pos*/) { popup(QCursor::pos()); } void QmitkSemanticRelationsContextMenu::InitDefaultActions() { m_ControlPointAction = new QmitkDataNodeSetControlPointAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_ControlPointAction); m_InformationTypeAction = new QmitkDataNodeSetInformationTypeAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_InformationTypeAction); m_UnlinkFromLesionAction = new QmitkDataNodeUnlinkFromLesionAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_UnlinkFromLesionAction); m_RemoveFromSemanticRelationsAction = new QmitkDataNodeRemoveFromSemanticRelationsAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_RemoveFromSemanticRelationsAction); m_OpenInAction = new QmitkDataNodeOpenInAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_OpenInAction); } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h index 73daef38ff..99366a64b8 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h @@ -1,75 +1,75 @@ /*=================================================================== 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 QMITKSEMANTICRELATIONSCONTEXTMENU_H #define QMITKSEMANTICRELATIONSCONTEXTMENU_H // semantic relations plugin #include "QmitkDataNodeSetControlPointAction.h" #include "QmitkDataNodeSetInformationTypeAction.h" #include "QmitkDataNodeUnlinkFromLesionAction.h" #include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" // mitk core #include #include // mitk render window manager module #include // mitk gui qt application plugin #include // blueberry ui qt plugin #include //qt #include class QmitkSemanticRelationsContextMenu : public QMenu { Q_OBJECT public: QmitkSemanticRelationsContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent = nullptr); virtual ~QmitkSemanticRelationsContextMenu() override; void SetDataStorage(mitk::DataStorage* dataStorage); - void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); + void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer); public Q_SLOTS: void OnContextMenuRequested(const QPoint&); private: void InitDefaultActions(); QWidget* m_Parent; berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite; mitk::WeakPointer m_DataStorage; - RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; + mitk::RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; QmitkDataNodeSetControlPointAction* m_ControlPointAction; QmitkDataNodeSetInformationTypeAction* m_InformationTypeAction; QmitkDataNodeUnlinkFromLesionAction* m_UnlinkFromLesionAction; QmitkDataNodeRemoveFromSemanticRelationsAction* m_RemoveFromSemanticRelationsAction; QmitkDataNodeOpenInAction* m_OpenInAction; }; #endif // QMITKSEMANTICRELATIONSCONTEXTMENU_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp index 2c5a87bcf4..6a20449fda 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,273 +1,273 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkSemanticRelationsView.h" #include "QmitkDataNodeAddToSemanticRelationsAction.h" #include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" // semantic relations module #include #include #include #include // mitk qt widgets module #include #include // mitk multi label module #include // berry #include #include // qt #include #include const std::string QmitkSemanticRelationsView::VIEW_ID = "org.mitk.views.semanticrelations"; void QmitkSemanticRelationsView::SetFocus() { // nothing here } void QmitkSemanticRelationsView::CreateQtPartControl(QWidget* parent) { // create GUI widgets m_Controls.setupUi(parent); m_LesionInfoWidget = new QmitkLesionInfoWidget(GetDataStorage(), parent); m_Controls.gridLayout->addWidget(m_LesionInfoWidget); m_PatientTableInspector = new QmitkPatientTableInspector(parent); m_PatientTableInspector->SetDataStorage(GetDataStorage()); m_Controls.gridLayout->addWidget(m_PatientTableInspector); QGridLayout* dndDataNodeWidgetLayout = new QGridLayout; dndDataNodeWidgetLayout->addWidget(m_PatientTableInspector, 0, 0); dndDataNodeWidgetLayout->setContentsMargins(0, 0, 0, 0); m_DnDDataNodeWidget = new QmitkDnDDataNodeWidget(parent); m_DnDDataNodeWidget->setLayout(dndDataNodeWidgetLayout); m_Controls.gridLayout->addWidget(m_DnDDataNodeWidget); m_ContextMenu = new QmitkSemanticRelationsContextMenu(GetSite(), m_PatientTableInspector); m_ContextMenu->SetDataStorage(GetDataStorage()); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { RenderWindowPartActivated(renderWindowPart); } SetUpConnections(); const auto& allCaseIDs = mitk::RelationStorage::GetAllCaseIDs(); for (const auto& caseID : allCaseIDs) { AddToComboBox(caseID); } } void QmitkSemanticRelationsView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { // connect QmitkRenderWindows - underlying vtkRenderWindow is the same as "mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows()" QHash windowMap = renderWindowPart->GetQmitkRenderWindows(); QHash::Iterator it; mitk::BaseRenderer* baseRenderer = nullptr; - RenderWindowLayerUtilities::RendererVector controlledRenderer; + mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer; for (it = windowMap.begin(); it != windowMap.end(); ++it) { baseRenderer = mitk::BaseRenderer::GetInstance(it.value()->GetVtkRenderWindow()); if (nullptr != baseRenderer) { controlledRenderer.push_back(baseRenderer); } } m_ContextMenu->SetControlledRenderer(controlledRenderer); } void QmitkSemanticRelationsView::SetUpConnections() { connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsView::OnCaseIDSelectionChanged); connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::LesionSelectionChanged, this, &QmitkSemanticRelationsView::OnLesionSelectionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::CurrentSelectionChanged, this, &QmitkSemanticRelationsView::OnDataNodeSelectionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::DataNodeDoubleClicked, this, &QmitkSemanticRelationsView::OnDataNodeDoubleClicked); connect(m_DnDDataNodeWidget, &QmitkDnDDataNodeWidget::NodesDropped, this, &QmitkSemanticRelationsView::OnNodesAdded); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnContextMenuRequested, m_ContextMenu, &QmitkSemanticRelationsContextMenu::OnContextMenuRequested); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnNodeRemoved, this, &QmitkSemanticRelationsView::NodeRemoved); } QItemSelectionModel* QmitkSemanticRelationsView::GetDataNodeSelectionModel() const { return m_PatientTableInspector->GetSelectionModel(); } void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::SemanticRelationsInference::InstanceExists(dataNode)) { // no observer needed for the integration; simply use a temporary instance for removing mitk::SemanticRelationsIntegration semanticRelationsIntegration; RemoveFromSemanticRelationsAction::Run(&semanticRelationsIntegration, dataNode); mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(dataNode); RemoveFromComboBox(caseID); } } void QmitkSemanticRelationsView::OnLesionSelectionChanged(const mitk::SemanticTypes::Lesion& lesion) { m_PatientTableInspector->SetLesion(lesion); } void QmitkSemanticRelationsView::OnDataNodeSelectionChanged(const QList& dataNodeSelection) { m_LesionInfoWidget->SetDataNodeSelection(dataNodeSelection); } void QmitkSemanticRelationsView::OnDataNodeDoubleClicked(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { OpenInEditor(dataNode); } else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { JumpToPosition(dataNode); } } void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) { m_LesionInfoWidget->SetCaseID(caseID.toStdString()); m_PatientTableInspector->SetCaseID(caseID.toStdString()); } void QmitkSemanticRelationsView::OnNodesAdded(std::vector nodes) { mitk::SemanticTypes::CaseID caseID = ""; for (mitk::DataNode* dataNode : nodes) { // no observer needed for the integration; simply use a temporary instance for adding mitk::SemanticRelationsIntegration semanticRelationsIntegration; AddToSemanticRelationsAction::Run(&semanticRelationsIntegration, GetDataStorage(), dataNode); caseID = mitk::GetCaseIDFromDataNode(dataNode); AddToComboBox(caseID); } } void QmitkSemanticRelationsView::OnNodeRemoved(const mitk::DataNode* dataNode) { NodeRemoved(dataNode); } void QmitkSemanticRelationsView::AddToComboBox(const mitk::SemanticTypes::CaseID& caseID) { int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (-1 == foundIndex) { // add the caseID to the combo box, as it is not already contained m_Controls.caseIDComboBox->addItem(QString::fromStdString(caseID)); } } void QmitkSemanticRelationsView::RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID) { std::vector allControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(caseID); int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (allControlPoints.empty() && -1 != foundIndex) { // caseID does not contain any control points and therefore no data // remove the caseID, if it is still contained m_Controls.caseIDComboBox->removeItem(foundIndex); } } void QmitkSemanticRelationsView::OpenInEditor(const mitk::DataNode* dataNode) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::BRING_TO_FRONT | mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto image = dynamic_cast(dataNode->GetData()); if (nullptr != image) { mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkSemanticRelationsView::JumpToPosition(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } mitk::LabelSetImage* labelSetImage = dynamic_cast(dataNode->GetData()); if (nullptr == labelSetImage) { return; } unsigned int activeLayer = labelSetImage->GetActiveLayer(); mitk::Label* activeLabel = labelSetImage->GetActiveLabel(activeLayer); labelSetImage->UpdateCenterOfMass(activeLabel->GetValue(), activeLayer); const mitk::Point3D& centerPosition = activeLabel->GetCenterOfMassCoordinates(); if (centerPosition.GetVnlVector().max_value() > 0.0) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::BRING_TO_FRONT | mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto segmentation = dynamic_cast(dataNode->GetData()); if (nullptr != segmentation) { renderWindowPart->SetSelectedPosition(centerPosition); mitk::RenderingManager::GetInstance()->InitializeViews(segmentation->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } } diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/plugin.xml b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/plugin.xml index 580dba9b9d..aac0c76d78 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/plugin.xml +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/plugin.xml @@ -1,28 +1,29 @@