diff --git a/Base/QTGUI/qSlicerMouseModeToolBar.cxx b/Base/QTGUI/qSlicerMouseModeToolBar.cxx index 2f5ffe80a0aaf2cd1e09b8fe9e6635e95f4fd3fc..8af6201d6c53daabb6faa8fae5cfbfc9f9b1de46 100644 --- a/Base/QTGUI/qSlicerMouseModeToolBar.cxx +++ b/Base/QTGUI/qSlicerMouseModeToolBar.cxx @@ -123,11 +123,7 @@ void qSlicerMouseModeToolBarPrivate::setMRMLScene(vtkMRMLScene* newScene) this->MRMLScene = newScene; // watch for changes to the interaction, selection nodes so can update the widget - vtkMRMLInteractionNode* interactionNode = - (this->MRMLAppLogic && this->MRMLScene) ? - this->MRMLAppLogic->GetInteractionNode() : 0; - this->qvtkReconnect(interactionNode, vtkCommand::ModifiedEvent, - this, SLOT(updateWidgetFromInteractionNode())); + q->setInteractionNode((this->MRMLAppLogic && this->MRMLScene) ? this->MRMLAppLogic->GetInteractionNode() : 0); vtkMRMLSelectionNode* selectionNode = (this->MRMLAppLogic && this->MRMLScene) ? @@ -249,8 +245,8 @@ void qSlicerMouseModeToolBarPrivate::updateWidgetFromSelectionNode() //--------------------------------------------------------------------------- void qSlicerMouseModeToolBarPrivate::updateWidgetFromInteractionNode() { - vtkMRMLInteractionNode* interactionNode = - this->MRMLAppLogic ? this->MRMLAppLogic->GetInteractionNode() : 0; + Q_Q(qSlicerMouseModeToolBar); + vtkMRMLInteractionNode* interactionNode = q->interactionNode(); if (!interactionNode) { qDebug() << "Mouse Mode ToolBar: no interaction node"; @@ -355,6 +351,8 @@ void qSlicerMouseModeToolBarPrivate::onMRMLSceneEndBatchProcess() // re-enable in case it didn't get re-enabled for scene load q->setEnabled(true); + q->setInteractionNode((this->MRMLAppLogic && this->MRMLScene) ? this->MRMLAppLogic->GetInteractionNode() : 0); + // update the state from mrml this->updateWidgetFromMRML(); } @@ -421,7 +419,7 @@ void qSlicerMouseModeToolBar::switchToViewTransformMode() return; } - vtkMRMLInteractionNode * interactionNode = d->MRMLAppLogic->GetInteractionNode(); + vtkMRMLInteractionNode * interactionNode = this->interactionNode(); if (interactionNode) { // update the interaction node, should trigger a cursor update @@ -469,6 +467,11 @@ void qSlicerMouseModeToolBar::changeCursorTo(QCursor cursor) { return; } + // Update cursor only if view interaction node corresponds to the one associated with the mouse toolbar + if (threeDView->mrmlViewNode()->GetInteractionNode() != this->interactionNode()) + { + continue; + } threeDView->setCursor(cursor); #if VTK_MAJOR_VERSION >= 9 || (VTK_MAJOR_VERSION >= 8 && VTK_MINOR_VERSION >= 2) threeDView->VTKWidget()->setQVTKCursor(cursor); @@ -483,6 +486,11 @@ void qSlicerMouseModeToolBar::changeCursorTo(QCursor cursor) { return; } + // Update cursor only if view interaction node corresponds to the one associated with the mouse toolbar + if (sliceView->mrmlSliceNode()->GetInteractionNode() != this->interactionNode()) + { + continue; + } sliceView->setCursor(cursor); #if VTK_MAJOR_VERSION >= 9 || (VTK_MAJOR_VERSION >= 8 && VTK_MINOR_VERSION >= 2) sliceView->VTKWidget()->setQVTKCursor(cursor); @@ -528,7 +536,7 @@ void qSlicerMouseModeToolBar::switchPlaceMode() QString previousPlaceNodeClassName = QString(selectionNode->GetActivePlaceNodeClassName()); selectionNode->SetReferenceActivePlaceNodeClassName(placeNodeClassName.toLatin1()); // update the interaction mode, which will trigger an update of the cursor - vtkMRMLInteractionNode * interactionNode = d->MRMLAppLogic->GetInteractionNode(); + vtkMRMLInteractionNode * interactionNode = this->interactionNode(); if (interactionNode) { // is this a click on top of a single or persistent place mode? @@ -571,11 +579,7 @@ QAction* qSlicerMouseModeToolBar::actionFromPlaceNodeClassName(QString placeNode //--------------------------------------------------------------------------- void qSlicerMouseModeToolBar::setPersistence(bool persistent) { - Q_D(qSlicerMouseModeToolBar); - - vtkMRMLInteractionNode *interactionNode = - d->MRMLAppLogic ? d->MRMLAppLogic->GetInteractionNode() : 0; - + vtkMRMLInteractionNode *interactionNode = this->interactionNode(); if (interactionNode) { interactionNode->SetPlaceModePersistence(persistent ? 1 : 0); @@ -615,3 +619,23 @@ void qSlicerMouseModeToolBar::setDefaultPlaceClassName(const QString& className) Q_D(qSlicerMouseModeToolBar); d->DefaultPlaceClassName = className; } + +//----------------------------------------------------------------------------- +vtkMRMLInteractionNode* qSlicerMouseModeToolBar::interactionNode()const +{ + Q_D(const qSlicerMouseModeToolBar); + return d->InteractionNode; +} + +//----------------------------------------------------------------------------- +void qSlicerMouseModeToolBar::setInteractionNode(vtkMRMLInteractionNode* interactionNode) +{ + Q_D(qSlicerMouseModeToolBar); + if (d->InteractionNode == interactionNode) + { + return; + } + d->qvtkReconnect(d->InteractionNode, interactionNode, vtkCommand::ModifiedEvent, + d, SLOT(updateWidgetFromInteractionNode())); + d->InteractionNode = interactionNode; +} diff --git a/Base/QTGUI/qSlicerMouseModeToolBar.h b/Base/QTGUI/qSlicerMouseModeToolBar.h index 1a37c3b14f8c3480c7103760ef49d7fb2107baec..1844708f81af9e8f8cbb928f22c6f604abbe265a 100644 --- a/Base/QTGUI/qSlicerMouseModeToolBar.h +++ b/Base/QTGUI/qSlicerMouseModeToolBar.h @@ -29,6 +29,7 @@ #include "qSlicerBaseQTGUIExport.h" class qSlicerMouseModeToolBarPrivate; +class vtkMRMLInteractionNode; class vtkMRMLScene; class vtkSlicerApplicationLogic; @@ -58,6 +59,10 @@ public: QString defaultPlaceClassName()const; void setDefaultPlaceClassName(const QString& className); + /// Get interaction node. + /// \sa setInteractionNode() + Q_INVOKABLE vtkMRMLInteractionNode* interactionNode()const; + public slots: /// Set the application logic. It is used to retrieve the selection and @@ -77,6 +82,10 @@ public slots: /// Update the interaction node's persistent place mode from the UI void setPersistence(bool persistent); + /// Set interaction node used to update the toolbar. + /// \sa interactionNode() + void setInteractionNode(vtkMRMLInteractionNode* interactionNode); + protected: QScopedPointer d_ptr; diff --git a/Base/QTGUI/qSlicerMouseModeToolBar_p.h b/Base/QTGUI/qSlicerMouseModeToolBar_p.h index c748ce25aa74ecdf6a6c8a12a69179e8696ee47d..b62cb556559397d3e6c96a3a63d5d30eb8819493 100644 --- a/Base/QTGUI/qSlicerMouseModeToolBar_p.h +++ b/Base/QTGUI/qSlicerMouseModeToolBar_p.h @@ -53,6 +53,7 @@ // VTK includes #include +#include class qSlicerMouseModeToolBarPrivate; class QAction; @@ -92,6 +93,7 @@ public: vtkSmartPointer MRMLScene; vtkSmartPointer MRMLAppLogic; + vtkWeakPointer InteractionNode; /// PlaceMode button and menu QToolButton *CreateAndPlaceToolButton; diff --git a/Libs/MRML/Core/Testing/vtkMRMLViewNodeTest1.cxx b/Libs/MRML/Core/Testing/vtkMRMLViewNodeTest1.cxx index b56413f709d5cc242d17e67b9aa45d828e7b0627..11a2b19fdca2d3fa89ac6aad8edf8cac15aa823c 100644 --- a/Libs/MRML/Core/Testing/vtkMRMLViewNodeTest1.cxx +++ b/Libs/MRML/Core/Testing/vtkMRMLViewNodeTest1.cxx @@ -11,11 +11,42 @@ =========================================================================auto=*/ #include "vtkMRMLCoreTestingMacros.h" +#include "vtkMRMLInteractionNode.h" +#include "vtkMRMLScene.h" #include "vtkMRMLViewNode.h" int vtkMRMLViewNodeTest1(int , char * [] ) { vtkNew node1; EXERCISE_ALL_BASIC_MRML_METHODS(node1.GetPointer()); + + // Test Set/GetInteractionNode without scene + { + vtkNew viewNode; + vtkNew interactionNode; + CHECK_NULL(viewNode->GetInteractionNode()); + viewNode->SetInteractionNode(interactionNode.GetPointer()); + CHECK_NULL(viewNode->GetInteractionNode()); + } + + // Test Set/GetInteractionNode with scene + { + vtkNew scene; + vtkNew viewNode; + vtkNew interactionNode; // interaction node is a singleton by default + scene->AddNode(viewNode.GetPointer()); + scene->AddNode(interactionNode.GetPointer()); + CHECK_POINTER(viewNode->GetInteractionNode(), interactionNode.GetPointer()); + CHECK_POINTER(viewNode->GetInteractionNode(), scene->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + + vtkNew otherInteractionNode; + otherInteractionNode->SetSingletonOff(); + scene->AddNode(otherInteractionNode.GetPointer()); + CHECK_POINTER(viewNode->GetInteractionNode(), scene->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + viewNode->SetInteractionNode(otherInteractionNode.GetPointer()); + CHECK_POINTER(viewNode->GetInteractionNode(), otherInteractionNode.GetPointer()); + CHECK_POINTER_DIFFERENT(otherInteractionNode.GetPointer(), scene->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + } + return EXIT_SUCCESS; } diff --git a/Libs/MRML/Core/vtkMRMLAbstractViewNode.cxx b/Libs/MRML/Core/vtkMRMLAbstractViewNode.cxx index 7db383e3965c9b9e2dda10e14f6b6cbdebf6394c..7dd2bac2732b13283f0044b6805d4eea2d43f11e 100644 --- a/Libs/MRML/Core/vtkMRMLAbstractViewNode.cxx +++ b/Libs/MRML/Core/vtkMRMLAbstractViewNode.cxx @@ -23,6 +23,7 @@ // MRML includes #include "vtkMRMLAbstractViewNode.h" +#include "vtkMRMLInteractionNode.h" #include "vtkMRMLModelNode.h" #include "vtkMRMLScene.h" @@ -31,6 +32,7 @@ const char* vtkMRMLAbstractViewNode::OrientationMarkerHumanModelReferenceRole = "OrientationMarkerHumanModel"; const char* vtkMRMLAbstractViewNode::ParentLayoutNodeReferenceRole = "ParentLayoutNodeRef"; +const char* vtkMRMLAbstractViewNode::InteractionNodeReferenceRole = "InteractionNodeRef"; const int vtkMRMLAbstractViewNode::AxisLabelsCount = 6; static const char* DEFAULT_AXIS_LABELS[vtkMRMLAbstractViewNode::AxisLabelsCount] = {"L", "R", "P", "A", "I", "S"}; @@ -293,6 +295,40 @@ void vtkMRMLAbstractViewNode::PrintSelf(ostream& os, vtkIndent indent) } //------------------------------------------------------------------------------ +vtkMRMLInteractionNode* vtkMRMLAbstractViewNode::GetInteractionNode() +{ + vtkMRMLInteractionNode * interactionNode = + vtkMRMLInteractionNode::SafeDownCast(this->GetNodeReference(this->InteractionNodeReferenceRole)); + if (this->GetScene() && !interactionNode) + { + interactionNode = vtkMRMLInteractionNode::SafeDownCast ( + this->GetScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + } + return interactionNode; +} + +//------------------------------------------------------------------------------ +bool vtkMRMLAbstractViewNode::SetInteractionNodeID(const char *interactionNodeId) +{ + if (!interactionNodeId) + { + return false; + } + this->SetNodeReferenceID(this->InteractionNodeReferenceRole, interactionNodeId); + return true; +} + +//------------------------------------------------------------------------------ +bool vtkMRMLAbstractViewNode::SetInteractionNode(vtkMRMLNode* node) +{ + if (node && this->Scene != node->GetScene()) + { + vtkErrorMacro("Cannot set reference: the referenced and referencing node are not in the same scene"); + return false; + } + return this->SetInteractionNodeID(node ? node->GetID() : NULL); +} + int vtkMRMLAbstractViewNode::IsMappedInLayout() { if (!this->GetAttribute("MappedInLayout")) diff --git a/Libs/MRML/Core/vtkMRMLAbstractViewNode.h b/Libs/MRML/Core/vtkMRMLAbstractViewNode.h index 59c372c1034249a3c8fe93879133a2108754bf3c..133c02b9bb8dd16b516262605ad960d0735c8644 100644 --- a/Libs/MRML/Core/vtkMRMLAbstractViewNode.h +++ b/Libs/MRML/Core/vtkMRMLAbstractViewNode.h @@ -27,6 +27,7 @@ // MRML includes #include "vtkMRMLNode.h" +class vtkMRMLInteractionNode; class vtkMRMLModelNode; class vtkStringArray; @@ -98,6 +99,32 @@ public: vtkGetMacro(Visibility, int); vtkSetMacro(Visibility, int); + /// \brief Get interaction node. + /// + /// If no node reference has been explicitly set using SetInteractionNode() + /// or SetInteractionNodeID(), return the singleton interaction node. + /// + /// The singleton interaction node is considered to be the default interaction node. Associating + /// a specific interaction node to one or a multiple views allows to control the interaction mode + /// associated with these views. + /// + /// Since by default, the interaction node is a singleton, a new interaction node may be + /// created doing the following: + /// + /// \code{.cpp} + /// vtkNew interactionNode; + /// interactionNode->SetSingletonOff(); + /// this->GetMRMLScene()->AddNode(interactionNode.GetPointer()); + /// \endcode + /// + /// \sa SetInteractionNodeID() SetInteractionNode() + vtkMRMLInteractionNode* GetInteractionNode(); + /// Set interaction node reference. + /// \sa GetInteractionNode() + bool SetInteractionNodeID(const char *interactionNodeId); + /// Set interaction node reference. + /// \sa GetInteractionNode() + bool SetInteractionNode(vtkMRMLNode* node); /// Indicates whether or not the view is mapped in the current layout. /// \sa GetVisibility() @@ -286,6 +313,7 @@ protected: vtkSmartPointer AxisLabels; static const char* ParentLayoutNodeReferenceRole; + static const char* InteractionNodeReferenceRole; }; //------------------------------------------------------------------------------ diff --git a/Libs/MRML/DisplayableManager/vtkMRMLAbstractDisplayableManager.cxx b/Libs/MRML/DisplayableManager/vtkMRMLAbstractDisplayableManager.cxx index e6529a578b735c736f9509cd49ec4208cea1f736..3b0827265aa63bc3996032f2075e14bc4fd52e0f 100644 --- a/Libs/MRML/DisplayableManager/vtkMRMLAbstractDisplayableManager.cxx +++ b/Libs/MRML/DisplayableManager/vtkMRMLAbstractDisplayableManager.cxx @@ -27,6 +27,7 @@ #include // MRML includes +#include #include #include #include @@ -532,6 +533,9 @@ vtkMRMLAbstractDisplayableManager::vtkMRMLAbstractDisplayableManager() this->AddObserver(vtkCommand::DeleteEvent, this->Internal->DeleteCallBackCommand); // Default observable event associated with DisplayableNode this->AddMRMLDisplayableManagerEvent(vtkCommand::ModifiedEvent); + this->AddMRMLDisplayableManagerEvent(vtkMRMLNode::ReferenceAddedEvent); + this->AddMRMLDisplayableManagerEvent(vtkMRMLNode::ReferenceRemovedEvent); + this->AddMRMLDisplayableManagerEvent(vtkMRMLNode::ReferenceModifiedEvent); // Setup widgets callback vtkObserverManager * widgetsObserver = this->Internal->WidgetsObserverManager; @@ -577,9 +581,7 @@ void vtkMRMLAbstractDisplayableManager::CreateIfPossible() assert(this->GetMRMLDisplayableNode()); // Look for InteractionNode - this->Internal->MRMLInteractionNode = vtkMRMLInteractionNode::SafeDownCast( - this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); - if (!this->Internal->MRMLInteractionNode) + if (!this->GetInteractionNode()) { vtkWarningMacro( << "CreateIfPossible - MRMLScene does NOT contain any InteractionNode"); } @@ -699,11 +701,29 @@ int vtkMRMLAbstractDisplayableManager::ActiveInteractionModes() { void vtkMRMLAbstractDisplayableManager::ProcessMRMLNodesEvents( vtkObject* caller, unsigned long event, void * callData) { - if (caller == this->GetMRMLDisplayableNode() && - event == vtkCommand::ModifiedEvent) - { - this->OnMRMLDisplayableNodeModifiedEvent(caller); - return; + if (caller == this->GetMRMLDisplayableNode()) + { + if(event == vtkCommand::ModifiedEvent) + { + this->OnMRMLDisplayableNodeModifiedEvent(caller); + return; + } + else if(event == vtkMRMLNode::ReferenceAddedEvent || + event == vtkMRMLNode::ReferenceRemovedEvent || + event == vtkMRMLNode::ReferenceModifiedEvent) + { + // Update interaction node + vtkMRMLAbstractViewNode* viewNode = vtkMRMLAbstractViewNode::SafeDownCast(this->GetMRMLDisplayableNode()); + if (viewNode) + { + this->Internal->SetAndObserveMRMLInteractionNode(viewNode->GetInteractionNode()); + } + else + { + vtkErrorMacro(<< "ProcessMRMLNodesEvents failed: " + << "No viewNode is associated with the displayable manager: " << this->GetClassName()); + } + } } this->Superclass::ProcessMRMLNodesEvents(caller, event, callData); } @@ -791,17 +811,16 @@ void vtkMRMLAbstractDisplayableManager::SetAndObserveMRMLDisplayableNode( { // Observe scene associated with the MRML DisplayableNode vtkMRMLScene * sceneToObserve = 0; - if (newMRMLDisplayableNode) + vtkMRMLAbstractViewNode* viewNode = vtkMRMLAbstractViewNode::SafeDownCast(newMRMLDisplayableNode); + if (viewNode) { - sceneToObserve = newMRMLDisplayableNode->GetScene(); + sceneToObserve = viewNode->GetScene(); // Observe InteractionNode - vtkMRMLInteractionNode *interactionNode = vtkMRMLInteractionNode::SafeDownCast ( - sceneToObserve->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + vtkMRMLInteractionNode *interactionNode = viewNode->GetInteractionNode(); + this->Internal->SetAndObserveMRMLInteractionNode(interactionNode); if (interactionNode) { - // Observe MRML InteractionNode only if a valid MRML DisplayableNode is set - this->Internal->SetAndObserveMRMLInteractionNode(newMRMLDisplayableNode ? interactionNode : 0); this->Internal->UpdateInteractorStyle(); } else @@ -811,12 +830,12 @@ void vtkMRMLAbstractDisplayableManager::SetAndObserveMRMLDisplayableNode( } } vtkSetAndObserveMRMLNodeEventsMacro(this->Internal->MRMLDisplayableNode, - newMRMLDisplayableNode, + viewNode, this->Internal->MRMLDisplayableNodeObservableEvents); this->SetMRMLScene(sceneToObserve); this->SetUpdateFromMRMLRequested(true); this->CreateIfPossible(); - if (newMRMLDisplayableNode != 0) + if (viewNode != 0) { this->RequestRender(); } diff --git a/Libs/MRML/DisplayableManager/vtkSliceViewInteractorStyle.cxx b/Libs/MRML/DisplayableManager/vtkSliceViewInteractorStyle.cxx index 3e7ad57500cb381996ebfa30438d9795cade1973..b0975883508515a7961cfbbe0630bb1e72209c8a 100644 --- a/Libs/MRML/DisplayableManager/vtkSliceViewInteractorStyle.cxx +++ b/Libs/MRML/DisplayableManager/vtkSliceViewInteractorStyle.cxx @@ -340,9 +340,12 @@ int vtkSliceViewInteractorStyle::GetMouseInteractionMode() vtkErrorMacro("vtkSliceViewInteractorStyle::GetMouseInteractionMode: failed to get scene"); return vtkMRMLInteractionNode::ViewTransform; } - vtkMRMLScene* scene = this->SliceLogic->GetMRMLScene(); - - vtkMRMLInteractionNode *interactionNode = vtkMRMLInteractionNode::SafeDownCast(scene->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + if ( this->SliceLogic->GetSliceNode() == 0 ) + { + vtkErrorMacro("vtkSliceViewInteractorStyle::GetMouseInteractionMode: failed to get slice view node"); + return vtkMRMLInteractionNode::ViewTransform; + } + vtkMRMLInteractionNode *interactionNode = this->SliceLogic->GetSliceNode()->GetInteractionNode(); if (interactionNode == 0) { vtkErrorMacro("vtkSliceViewInteractorStyle::GetMouseInteractionMode: failed to get interaction node"); diff --git a/Libs/MRML/DisplayableManager/vtkThreeDViewInteractorStyle.cxx b/Libs/MRML/DisplayableManager/vtkThreeDViewInteractorStyle.cxx index e4557b60061642a46024c200e02ea84331083b70..227b7730553a3fbd7501157849994afa94db3577 100644 --- a/Libs/MRML/DisplayableManager/vtkThreeDViewInteractorStyle.cxx +++ b/Libs/MRML/DisplayableManager/vtkThreeDViewInteractorStyle.cxx @@ -325,8 +325,14 @@ void vtkThreeDViewInteractorStyle::OnLeftButtonDown() if ( this->GetCameraNode() != 0 && this->GetCameraNode()->GetScene() != 0 ) { - interactionNode = vtkMRMLInteractionNode::SafeDownCast( - this->GetCameraNode()->GetScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + vtkMRMLAbstractViewNode* viewNode = vtkMRMLAbstractViewNode::SafeDownCast( + this->GetCameraNode()->GetScene()->GetNodeByID(this->GetCameraNode()->GetActiveTag())); + if (!viewNode) + { + vtkErrorMacro("OnLeftButtonDown: failed to lookup view node associated with camera node = " + << this->GetCameraNode()->GetID()); + } + interactionNode = viewNode ? viewNode->GetInteractionNode() : 0; if (interactionNode != 0) { @@ -399,8 +405,14 @@ void vtkThreeDViewInteractorStyle::OnLeftButtonUp() if ( this->GetCameraNode() != 0 && this->GetCameraNode()->GetScene() != 0 ) { - interactionNode = vtkMRMLInteractionNode::SafeDownCast( - this->GetCameraNode()->GetScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + vtkMRMLAbstractViewNode* viewNode = vtkMRMLAbstractViewNode::SafeDownCast( + this->GetCameraNode()->GetScene()->GetNodeByID(this->GetCameraNode()->GetActiveTag())); + if (!viewNode) + { + vtkErrorMacro("OnLeftButtonUp: failed to lookup view node associated with camera node = " + << this->GetCameraNode()->GetID()); + } + interactionNode = viewNode ? viewNode->GetInteractionNode() : 0; if (interactionNode != 0) { diff --git a/Libs/MRML/Logic/vtkMRMLApplicationLogic.h b/Libs/MRML/Logic/vtkMRMLApplicationLogic.h index b803e10eacfc6bfb973821abec6409da5f35705d..d031d3ad9e898e77c6bc70b0e71383964c3463a2 100644 --- a/Libs/MRML/Logic/vtkMRMLApplicationLogic.h +++ b/Libs/MRML/Logic/vtkMRMLApplicationLogic.h @@ -54,10 +54,10 @@ public: void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; vtkTypeMacro(vtkMRMLApplicationLogic, vtkMRMLAbstractLogic); - /// Get current Selection node + /// Get default Selection node vtkMRMLSelectionNode* GetSelectionNode()const; - /// Get current Interaction node + /// Get default Interaction node vtkMRMLInteractionNode* GetInteractionNode()const; /// All the slice logics in the application diff --git a/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.cxx b/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.cxx index 7a92eb0389c1618f9aa60249d61d6989507f3904..c73dc889580d69ec07a02d08818f6938743965cb 100644 --- a/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.cxx +++ b/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.cxx @@ -319,7 +319,7 @@ char *vtkSlicerAnnotationModuleLogic::AddFiducial(double r, double a, double s, //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -void vtkSlicerAnnotationModuleLogic::ProcessMRMLNodesEvents(vtkObject *caller, +void vtkSlicerAnnotationModuleLogic::ProcessMRMLNodesEvents(vtkObject *vtkNotUsed(caller), unsigned long event, void *callData) { @@ -510,11 +510,9 @@ void vtkSlicerAnnotationModuleLogic::AddAnnotationNode(const char * nodeDescript //--------------------------------------------------------------------------- // Start the place mouse mode //--------------------------------------------------------------------------- -void vtkSlicerAnnotationModuleLogic::StartPlaceMode(bool persistent) +void vtkSlicerAnnotationModuleLogic::StartPlaceMode(bool persistent, vtkMRMLInteractionNode* interactionNode) { - - vtkMRMLInteractionNode *interactionNode = NULL; - if ( this->GetMRMLScene()) + if (!interactionNode && this->GetMRMLScene()) { interactionNode = vtkMRMLInteractionNode::SafeDownCast(this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); } @@ -558,7 +556,7 @@ void vtkSlicerAnnotationModuleLogic::AddNodeCompleted(vtkMRMLAnnotationNode* ann //--------------------------------------------------------------------------- // Exit the place mode //--------------------------------------------------------------------------- -void vtkSlicerAnnotationModuleLogic::StopPlaceMode(bool persistent) +void vtkSlicerAnnotationModuleLogic::StopPlaceMode(bool persistent, vtkMRMLInteractionNode* interactionNode) { vtkMRMLSelectionNode *selectionNode = NULL; @@ -573,9 +571,10 @@ void vtkSlicerAnnotationModuleLogic::StopPlaceMode(bool persistent) return; } - vtkMRMLInteractionNode *interactionNode = - vtkMRMLInteractionNode::SafeDownCast( - this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + if (!interactionNode && this->GetMRMLScene()) + { + interactionNode = vtkMRMLInteractionNode::SafeDownCast(this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + } if (interactionNode == NULL) { vtkErrorMacro ( "StopPlaceMode: No interaction node in the scene." ); @@ -609,15 +608,12 @@ void vtkSlicerAnnotationModuleLogic::StopPlaceMode(bool persistent) //--------------------------------------------------------------------------- // Cancel the current placement or remove the last placed node //--------------------------------------------------------------------------- -void vtkSlicerAnnotationModuleLogic::CancelCurrentOrRemoveLastAddedAnnotationNode() +void vtkSlicerAnnotationModuleLogic::CancelCurrentOrRemoveLastAddedAnnotationNode(vtkMRMLInteractionNode* interactionNode) { - - vtkMRMLInteractionNode *interactionNode = NULL; - if (this->GetMRMLScene()) + if (!interactionNode && this->GetMRMLScene()) { interactionNode = vtkMRMLInteractionNode::SafeDownCast(this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); } - if (!interactionNode) { vtkErrorMacro("CancelCurrentOrRemoveLastAddedAnnotationNode: No interaction node") diff --git a/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.h b/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.h index 4e06407405e7aeff6cdaa12c1f24af8c465fbcdb..9b8235c51337643974f215797f2e2b7f969502cf 100644 --- a/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.h +++ b/Modules/Loadable/Annotations/Logic/vtkSlicerAnnotationModuleLogic.h @@ -28,11 +28,13 @@ public: vtkTypeMacro(vtkSlicerAnnotationModuleLogic,vtkSlicerModuleLogic); virtual void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; - // Start the place mode for annotations - void StartPlaceMode(bool persistent=false); + /// Start the place mode for annotations. + /// By default, the singleton interaction node is updated. + void StartPlaceMode(bool persistent=false, vtkMRMLInteractionNode* interactionNode = NULL); - // Exit the place mode for annotations - void StopPlaceMode(bool persistent=false); + /// Exit the place mode for annotations. + /// By default, the singleton interaction node is updated. + void StopPlaceMode(bool persistent=false, vtkMRMLInteractionNode* interactionNode = NULL); // Start adding a new annotation Node void AddAnnotationNode(const char * nodeDescriptor, bool persistent=false); @@ -40,8 +42,9 @@ public: // After a node was added, propagate to widget void AddNodeCompleted(vtkMRMLAnnotationNode* annotationNode); - // Cancel the current annotation placement or remove last annotation node - void CancelCurrentOrRemoveLastAddedAnnotationNode(); + /// Cancel the current annotation placement or remove last annotation node. + /// By default, the singleton interaction node is updated. + void CancelCurrentOrRemoveLastAddedAnnotationNode(vtkMRMLInteractionNode* interactionNode = NULL); /// Remove an AnnotationNode and also its 1-1 IS-A hierarchyNode, if found. void RemoveAnnotationNode(vtkMRMLAnnotationNode* annotationNode); diff --git a/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.cxx b/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.cxx index b59a95f96246ea75311cfbb0e9d980efbe3c6215..651e3405895e13867cab35af99700ffb204c256c 100644 --- a/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.cxx +++ b/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.cxx @@ -338,10 +338,15 @@ void vtkSlicerMarkupsLogic::SetActiveListID(vtkMRMLMarkupsNode *markupsNode) if (activePlaceNodeClassName && strcmp(activePlaceNodeClassName, "vtkMRMLMarkupsFiducialNode") == 0) { selectionNode->SetActivePlaceNodeID(NULL); - vtkMRMLInteractionNode *interactionNode = vtkMRMLInteractionNode::SafeDownCast(this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); - if (interactionNode && interactionNode->GetCurrentInteractionMode() == vtkMRMLInteractionNode::Place) + vtkSmartPointer interactionNodes = vtkSmartPointer::Take + (this->GetMRMLScene()->GetNodesByClass("vtkMRMLInteractionNode")); + for(int interactionNodeIndex = 0; interactionNodeIndex < interactionNodes->GetNumberOfItems(); ++interactionNodeIndex) { - interactionNode->SetCurrentInteractionMode(vtkMRMLInteractionNode::ViewTransform); + vtkMRMLInteractionNode *interactionNode = vtkMRMLInteractionNode::SafeDownCast(interactionNodes->GetItemAsObject(interactionNodeIndex)); + if (interactionNode->GetCurrentInteractionMode() == vtkMRMLInteractionNode::Place) + { + interactionNode->SetCurrentInteractionMode(vtkMRMLInteractionNode::ViewTransform); + } } } return; @@ -1298,7 +1303,7 @@ void vtkSlicerMarkupsLogic::RenameAllMarkupsFromCurrentFormat(vtkMRMLMarkupsNode } //--------------------------------------------------------------------------- -bool vtkSlicerMarkupsLogic::StartPlaceMode(bool persistent) +bool vtkSlicerMarkupsLogic::StartPlaceMode(bool persistent, vtkMRMLInteractionNode* interactionNode) { if (!this->GetMRMLScene()) { @@ -1318,9 +1323,11 @@ bool vtkSlicerMarkupsLogic::StartPlaceMode(bool persistent) selectionNode->SetReferenceActivePlaceNodeClassName("vtkMRMLMarkupsFiducialNode"); // now go into place mode with the persistece flag set - vtkMRMLInteractionNode *interactionNode = - vtkMRMLInteractionNode::SafeDownCast( - this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + if (!interactionNode) + { + interactionNode = vtkMRMLInteractionNode::SafeDownCast( + this->GetMRMLScene()->GetNodeByID("vtkMRMLInteractionNodeSingleton")); + } if (!interactionNode) { vtkErrorMacro ("StartPlaceMode: No interaction node in the scene." ); diff --git a/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.h b/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.h index 21f47ef7de26816eb0ce761151d742a19c9373af..e5d0c1d0feb8b9106ad2fbcaad2d7a43df34c9f8 100644 --- a/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.h +++ b/Modules/Loadable/Markups/Logic/vtkSlicerMarkupsLogic.h @@ -185,8 +185,9 @@ public: /// Put the interaction node into place mode, and set the persistence of /// place mode according to the persistent flag. /// Return true on successfully going into place mode, false otherwise. + /// By default, the default interaction node is updated. /// \sa SetActiveIDList - bool StartPlaceMode(bool persistent); + bool StartPlaceMode(bool persistent, vtkMRMLInteractionNode* interactionNode = NULL); /// Inspect all the slice composite nodes in the scene. Return 1 if all have /// SliceIntersectionVisibility set to true, 0 if all have it set to false, diff --git a/Modules/Loadable/Markups/Widgets/Testing/Python/MarkupsWidgetsSelfTest.py b/Modules/Loadable/Markups/Widgets/Testing/Python/MarkupsWidgetsSelfTest.py index 05f2f095363e7b2acb8a326804a60c1cc31eb9a9..93baefd3430faeda2754d9b8efca4dd2eaad1b10 100644 --- a/Modules/Loadable/Markups/Widgets/Testing/Python/MarkupsWidgetsSelfTest.py +++ b/Modules/Loadable/Markups/Widgets/Testing/Python/MarkupsWidgetsSelfTest.py @@ -107,7 +107,7 @@ class MarkupsWidgetsSelfTestTest(ScriptedLoadableModuleTest): simpleMarkupsWidget = slicer.qSlicerSimpleMarkupsWidget() nodeSelector = slicer.util.findChildren(simpleMarkupsWidget,"MarkupsFiducialNodeComboBox")[0] - + self.assertIsNone(simpleMarkupsWidget.interactionNode()) simpleMarkupsWidget.setMRMLScene(slicer.mrmlScene) simpleMarkupsWidget.show() @@ -157,11 +157,19 @@ class MarkupsWidgetsSelfTestTest(ScriptedLoadableModuleTest): tableWidget = simpleMarkupsWidget.tableWidget() self.assertEqual(tableWidget.rowCount, numberOfFiducialsAdded) + self.assertEqual(simpleMarkupsWidget.interactionNode(), slicer.app.applicationLogic().GetInteractionNode()) + otherInteractionNode = slicer.vtkMRMLInteractionNode() + otherInteractionNode.SetSingletonOff() + slicer.mrmlScene.AddNode(otherInteractionNode) + simpleMarkupsWidget.setInteractionNode(otherInteractionNode) + self.assertEqual(simpleMarkupsWidget.interactionNode(), otherInteractionNode) + # ------------------------------------------------------------------------------ def section_MarkupsPlaceWidget(self): self.delayDisplay("Test MarkupsPlaceWidget",self.delayMs) placeWidget = slicer.qSlicerMarkupsPlaceWidget() + self.assertIsNone(placeWidget.interactionNode()) placeWidget.setMRMLScene(slicer.mrmlScene) placeWidget.setCurrentNode(self.markupsNode1) placeWidget.show() @@ -189,3 +197,10 @@ class MarkupsWidgetsSelfTestTest(ScriptedLoadableModuleTest): placeWidget.placeModeEnabled = False placeWidget.placeModeEnabled = True self.assertTrue(placeWidget.placeModePersistency) + + self.assertEqual(placeWidget.interactionNode(), slicer.app.applicationLogic().GetInteractionNode()) + otherInteractionNode = slicer.vtkMRMLInteractionNode() + otherInteractionNode.SetSingletonOff() + slicer.mrmlScene.AddNode(otherInteractionNode) + placeWidget.setInteractionNode(otherInteractionNode) + self.assertEqual(placeWidget.interactionNode(), otherInteractionNode) diff --git a/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.cxx b/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.cxx index e79b77f917a799e26a6e4b83b93a2ff531708590..e8d4a65c7edbde4813c15af9833da4cec55c0569 100644 --- a/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.cxx +++ b/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.cxx @@ -104,6 +104,7 @@ qSlicerMarkupsPlaceWidget::qSlicerMarkupsPlaceWidget(QWidget* parentWidget) : Su qSlicerMarkupsPlaceWidget::~qSlicerMarkupsPlaceWidget() { this->setCurrentNode(NULL); + this->setInteractionNode(NULL); } //----------------------------------------------------------------------------- @@ -180,6 +181,25 @@ vtkMRMLMarkupsFiducialNode* qSlicerMarkupsPlaceWidget::currentMarkupsFiducialNod return d->CurrentMarkupsNode; } +//----------------------------------------------------------------------------- +vtkMRMLInteractionNode* qSlicerMarkupsPlaceWidget::interactionNode()const +{ + Q_D(const qSlicerMarkupsPlaceWidget); + return d->InteractionNode; +} + +//----------------------------------------------------------------------------- +void qSlicerMarkupsPlaceWidget::setInteractionNode(vtkMRMLInteractionNode* interactionNode) +{ + Q_D(qSlicerMarkupsPlaceWidget); + if (d->InteractionNode == interactionNode) + { + return; + } + this->qvtkReconnect(d->InteractionNode, interactionNode, vtkCommand::ModifiedEvent, this, SLOT(updateWidget())); + d->InteractionNode = interactionNode; +} + //----------------------------------------------------------------------------- void qSlicerMarkupsPlaceWidget::setCurrentNode(vtkMRMLNode* currentNode) { @@ -448,10 +468,11 @@ void qSlicerMarkupsPlaceWidget::setMRMLScene(vtkMRMLScene* scene) interactionNode = vtkMRMLInteractionNode::SafeDownCast( d->MarkupsLogic->GetMRMLScene()->GetNodeByID( "vtkMRMLInteractionNodeSingleton" ) ); } + this->setInteractionNode(interactionNode); + this->qvtkReconnect(d->SelectionNode, selectionNode, vtkCommand::ModifiedEvent, this, SLOT(updateWidget())); - this->qvtkReconnect(d->InteractionNode, interactionNode, vtkCommand::ModifiedEvent, this, SLOT(updateWidget())); d->SelectionNode = selectionNode; - d->InteractionNode = interactionNode; + this->updateWidget(); } diff --git a/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.h b/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.h index 56386f95e463e231585edcca0baf9004329fe2c0..0c7487c8d941619b73fe94b3ed7a33df105fe89b 100644 --- a/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.h +++ b/Modules/Loadable/Markups/Widgets/qSlicerMarkupsPlaceWidget.h @@ -32,6 +32,7 @@ class qSlicerMarkupsPlaceWidgetPrivate; +class vtkMRMLInteractionNode; class vtkMRMLMarkupsFiducialNode; /// \ingroup Slicer_QtModules_CreateModels @@ -68,6 +69,10 @@ public: Q_INVOKABLE vtkMRMLMarkupsFiducialNode* currentMarkupsFiducialNode() const; + /// Get interaction node. + /// \sa setInteractionNode() + Q_INVOKABLE vtkMRMLInteractionNode* interactionNode()const; + /// Returns true if the current markups node is the active markups node in the scene. bool currentNodeActive() const; @@ -106,6 +111,10 @@ public slots: /// Set the currently selected markups node to be the active markups node in the Slicer scene. Does not change place mode. void setCurrentNodeActive(bool active); + /// Set interaction node used to update the widget. + /// \sa interactionNode() + void setInteractionNode(vtkMRMLInteractionNode* interactionNode); + void setDefaultNodeColor(QColor color); void setNodeColor(QColor color); diff --git a/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.cxx b/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.cxx index a5196cc1e2352ce1a723caa250b785373520d323..603151b32c1586751e45f379816ff3e2eb571fe8 100644 --- a/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.cxx +++ b/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.cxx @@ -192,6 +192,20 @@ void qSlicerSimpleMarkupsWidget::setCurrentNode(vtkMRMLNode* currentNode) emit markupsFiducialNodeChanged(); } +//----------------------------------------------------------------------------- +vtkMRMLInteractionNode* qSlicerSimpleMarkupsWidget::interactionNode()const +{ + Q_D(const qSlicerSimpleMarkupsWidget); + return d->MarkupsPlaceWidget->interactionNode(); +} + +//----------------------------------------------------------------------------- +void qSlicerSimpleMarkupsWidget::setInteractionNode(vtkMRMLInteractionNode* interactionNode) +{ + Q_D(qSlicerSimpleMarkupsWidget); + d->MarkupsPlaceWidget->setInteractionNode(interactionNode); +} + //----------------------------------------------------------------------------- void qSlicerSimpleMarkupsWidget::setNodeBaseName(QString newNodeBaseName) { diff --git a/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.h b/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.h index efee1be920c443f1008aec50e0c05289a90887e3..26da92012bb4015873a4f752e0d049525761705e 100644 --- a/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.h +++ b/Modules/Loadable/Markups/Widgets/qSlicerSimpleMarkupsWidget.h @@ -57,6 +57,10 @@ public: /// Deprecated. Use currentNode() instead. Q_INVOKABLE vtkMRMLNode* getCurrentNode(); + /// Get interaction node. + /// \sa setInteractionNode() + Q_INVOKABLE vtkMRMLInteractionNode* interactionNode()const; + /// Get the markups table widget Q_INVOKABLE QTableWidget* tableWidget() const; @@ -102,6 +106,10 @@ public slots: /// Set the default name of the markups node created in the combo box. void setNodeBaseName(QString newNodeBaseName); + /// Set interaction node used to update the widget. + /// \sa interactionNode() + void setInteractionNode(vtkMRMLInteractionNode* interactionNode); + /// Accessors to control place mode behavior void setEnterPlaceModeOnNodeChange(bool); diff --git a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx index 9d30f9933728fd01645777bde433e8950e711a26..9e305b5d05ddb151067990786bdb798f723980e6 100644 --- a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx +++ b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx @@ -1761,6 +1761,25 @@ void qMRMLSegmentEditorWidget::setMRMLSegmentEditorNode(vtkMRMLSegmentEditorNode this->updateWidgetFromMRML(); } +//----------------------------------------------------------------------------- +vtkMRMLInteractionNode* qMRMLSegmentEditorWidget::interactionNode()const +{ + Q_D(const qMRMLSegmentEditorWidget); + return d->InteractionNode; +} + +//----------------------------------------------------------------------------- +void qMRMLSegmentEditorWidget::setInteractionNode(vtkMRMLInteractionNode* interactionNode) +{ + Q_D(qMRMLSegmentEditorWidget); + if (d->InteractionNode == interactionNode) + { + return; + } + this->qvtkReconnect(d->InteractionNode, interactionNode, vtkCommand::ModifiedEvent, this, SLOT(onInteractionNodeModified())); + d->InteractionNode = interactionNode; +} + //------------------------------------------------------------------------------ void qMRMLSegmentEditorWidget::initializeParameterSetNode() { diff --git a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.h b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.h index ebbc7382255bd574fae6cfe6a7b4d9ada21f51e1..68a892033659dd292d6c61ce8c8f517e3f88de29 100644 --- a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.h +++ b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.h @@ -39,6 +39,7 @@ #include class vtkMRMLNode; +class vtkMRMLInteractionNode; class vtkMRMLSegmentationNode; class vtkMRMLSegmentEditorNode; class vtkMRMLVolumeNode; @@ -189,6 +190,10 @@ public: Q_INVOKABLE void masterVolumeNodeSelectorRemoveAttribute(const QString& nodeType, const QString& attributeName); + /// Get current interaction node. + /// \sa SetInteractionNode() + Q_INVOKABLE vtkMRMLInteractionNode* interactionNode() const; + public slots: /// Set the MRML \a scene associated with the widget virtual void setMRMLScene(vtkMRMLScene* newScene); @@ -286,6 +291,10 @@ public slots: /// labelmap representation axes. void rotateSliceViewsToSegmentation(); + /// Set node used to notify active effect about interaction node changes. + /// \sa interactionNode() + void setInteractionNode(vtkMRMLInteractionNode* interactionNode); + signals: /// Emitted if different segment is selected in the segment list. void currentSegmentIDChanged(const QString&);