Skip to content

Commit f7a16cb

Browse files
ENH: Add selection observer
- Add helper class to monitor the interaction / selection nodes
1 parent 10830a7 commit f7a16cb

File tree

9 files changed

+321
-11
lines changed

9 files changed

+321
-11
lines changed

LayerDM/CMakeLists.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
set(MODULE_NAME LayerDM)
44
set(MODULE_TITLE ${MODULE_NAME})
55

6-
set(${MODULE_NAME}_VERSION_MAJOR 1)
7-
set(${MODULE_NAME}_VERSION_MINOR 0)
8-
set(${MODULE_NAME}_VERSION_PATCH 0)
9-
10-
set(${MODULE_NAME}_VERSION "${${MODULE_NAME}_VERSION_MAJOR}.${${MODULE_NAME}_VERSION_MINOR}.${${MODULE_NAME}_VERSION_PATCH}")
11-
126
string(TOUPPER ${MODULE_NAME} MODULE_NAME_UPPER)
137

148
#-----------------------------------------------------------------------------

LayerDM/Logic/CMakeLists.txt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
project(vtkSlicer${MODULE_NAME}ModuleLogic)
22

33
set(KIT ${PROJECT_NAME})
4-
54
set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_LOGIC_EXPORT")
5+
set(${KIT}_INCLUDE_DIRECTORIES)
66

7-
set(${KIT}_INCLUDE_DIRECTORIES
8-
)
7+
set(LayerDM_VERSION_MAJOR 1)
8+
set(LayerDM_VERSION_MINOR 1)
9+
set(LayerDM_VERSION_PATCH 0)
10+
set(LayerDM_VERSION "${LayerDM_VERSION_MAJOR}.${LayerDM_VERSION_MINOR}.${LayerDM_VERSION_PATCH}")
911

1012
configure_file(
1113
${CMAKE_CURRENT_SOURCE_DIR}/vtkSlicerLayerDMVersion.h.in
@@ -20,6 +22,7 @@ set(${KIT}_SRCS
2022

2123
set(${KIT}_TARGET_LIBRARIES
2224
vtkSlicer${MODULE_NAME}ModuleMRML
25+
SlicerBaseLogic
2326
)
2427

2528
#-----------------------------------------------------------------------------
@@ -36,5 +39,5 @@ target_include_directories(
3639
PUBLIC
3740
${${KIT}_SOURCE_DIR}
3841
${${KIT}_BINARY_DIR}
39-
${Slicer_ModuleLogic_INCLUDE_DIRS}
42+
${Slicer_Base_INCLUDE_DIRS}
4043
)

LayerDM/MRML/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ set(${KIT}_SRCS
1212
vtkMRMLLayerDMNodeReferenceObserver.h
1313
vtkMRMLLayerDMObjectEventObserver.cxx
1414
vtkMRMLLayerDMObjectEventObserver.h
15+
vtkMRMLLayerDMSelectionObserver.cxx
16+
vtkMRMLLayerDMSelectionObserver.h
1517
vtkMRMLLayerDMWidgetEventTranslationNode.cxx
1618
vtkMRMLLayerDMWidgetEventTranslationNode.h
1719
)
@@ -28,7 +30,6 @@ endif ()
2830

2931
set(${KIT}_TARGET_LIBRARIES
3032
${MRML_LIBRARIES}
31-
SlicerBaseLogic
3233
)
3334

3435
#-----------------------------------------------------------------------------
@@ -47,4 +48,6 @@ target_include_directories(
4748
PUBLIC
4849
${${KIT}_SOURCE_DIR}
4950
${${KIT}_BINARY_DIR}
51+
${MRMLCore_INCLUDE_DIRS}
52+
${MRMLLogic_INCLUDE_DIRS}
5053
)

LayerDM/MRML/vtkMRMLLayerDMObjectEventObserver.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,20 @@ void vtkMRMLLayerDMObjectEventObserver::RemoveObserver(vtkObject* node)
134134

135135
this->m_obsMap.erase(node);
136136
}
137+
138+
vtkMRMLLayerDMObjectEventObserver::UpdateGuard::UpdateGuard(vtkMRMLLayerDMObjectEventObserver* obs)
139+
: m_obs(obs)
140+
{
141+
if (m_obs)
142+
{
143+
m_wasBlocked = m_obs->SetBlocked(true);
144+
}
145+
}
146+
147+
vtkMRMLLayerDMObjectEventObserver::UpdateGuard::~UpdateGuard()
148+
{
149+
if (m_obs)
150+
{
151+
m_obs->SetBlocked(m_wasBlocked);
152+
}
153+
}

LayerDM/MRML/vtkMRMLLayerDMObjectEventObserver.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class vtkCallbackCommand;
2525
class VTK_SLICER_LAYERDM_MODULE_MRML_EXPORT vtkMRMLLayerDMObjectEventObserver : public vtkObject
2626
{
2727
public:
28+
struct UpdateGuard;
2829
static vtkMRMLLayerDMObjectEventObserver* New();
2930
vtkTypeMacro(vtkMRMLLayerDMObjectEventObserver, vtkObject);
3031

@@ -53,6 +54,18 @@ class VTK_SLICER_LAYERDM_MODULE_MRML_EXPORT vtkMRMLLayerDMObjectEventObserver :
5354
/// @return previous blocked state.
5455
bool SetBlocked(bool isBlocked);
5556

57+
/// Helper update guard.
58+
/// Blocks update during struct lifetime for the given input observer.
59+
struct UpdateGuard
60+
{
61+
UpdateGuard(vtkMRMLLayerDMObjectEventObserver* obs);
62+
~UpdateGuard();
63+
64+
private:
65+
vtkMRMLLayerDMObjectEventObserver* m_obs;
66+
bool m_wasBlocked{};
67+
};
68+
5669
protected:
5770
vtkMRMLLayerDMObjectEventObserver();
5871
~vtkMRMLLayerDMObjectEventObserver() override;
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// LayerDM includes
2+
#include "vtkMRMLLayerDMObjectEventObserver.h"
3+
#include "vtkMRMLLayerDMSelectionObserver.h"
4+
5+
// Slicer includes
6+
#include <vtkMRMLScene.h>
7+
#include <vtkMRMLInteractionNode.h>
8+
#include <vtkMRMLSelectionNode.h>
9+
#include <vtkMRMLApplicationLogic.h>
10+
11+
// VTK includes
12+
#include <vtkObjectFactory.h>
13+
14+
vtkStandardNewMacro(vtkMRMLLayerDMSelectionObserver);
15+
16+
vtkMRMLLayerDMSelectionObserver::vtkMRMLLayerDMSelectionObserver()
17+
: m_obs{ vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver>::New() }
18+
{
19+
m_obs->SetUpdateCallback(
20+
[this](vtkObject* obj)
21+
{
22+
if (obj == this->m_interactionNode || obj == this->m_selectionNode)
23+
{
24+
this->Modified();
25+
}
26+
});
27+
}
28+
29+
vtkMRMLLayerDMSelectionObserver::~vtkMRMLLayerDMSelectionObserver() = default;
30+
31+
void vtkMRMLLayerDMSelectionObserver::SetScene(vtkMRMLScene* scene)
32+
{
33+
this->UpdateNodesFromScene(scene);
34+
}
35+
36+
void vtkMRMLLayerDMSelectionObserver::UpdateNodesFromScene(vtkMRMLScene* scene)
37+
{
38+
bool didModify{};
39+
didModify |= this->SetInteractionNode(vtkMRMLInteractionNode::SafeDownCast(scene ? scene->GetNodeByID("vtkMRMLInteractionNodeSingleton") : nullptr));
40+
didModify |= this->SetSelectionNode(vtkMRMLSelectionNode::SafeDownCast(scene ? scene->GetNodeByID("vtkMRMLSelectionNodeSingleton") : nullptr));
41+
if (didModify)
42+
{
43+
this->Modified();
44+
}
45+
}
46+
47+
void vtkMRMLLayerDMSelectionObserver::UpdateNodesFromApplicationLogic(vtkMRMLApplicationLogic* logic)
48+
{
49+
bool didModify{};
50+
didModify |= this->SetInteractionNode(logic ? logic->GetInteractionNode() : nullptr);
51+
didModify |= this->SetSelectionNode(logic ? logic->GetSelectionNode() : nullptr);
52+
if (didModify)
53+
{
54+
this->Modified();
55+
}
56+
}
57+
58+
bool vtkMRMLLayerDMSelectionObserver::SetInteractionNode(vtkMRMLInteractionNode* interactionNode)
59+
{
60+
const auto didModify = this->m_obs->UpdateObserver(m_interactionNode, interactionNode);
61+
this->m_interactionNode = interactionNode;
62+
return didModify;
63+
}
64+
65+
vtkMRMLInteractionNode* vtkMRMLLayerDMSelectionObserver::GetInteractionNode() const
66+
{
67+
return this->m_interactionNode;
68+
}
69+
70+
bool vtkMRMLLayerDMSelectionObserver::SetSelectionNode(vtkMRMLSelectionNode* selectionNode)
71+
{
72+
const auto didModify = this->m_obs->UpdateObserver(m_selectionNode, selectionNode);
73+
this->m_selectionNode = selectionNode;
74+
return didModify;
75+
}
76+
77+
vtkMRMLSelectionNode* vtkMRMLLayerDMSelectionObserver::GetSelectionNode() const
78+
{
79+
return this->m_selectionNode;
80+
}
81+
82+
bool vtkMRMLLayerDMSelectionObserver::IsPlacing(vtkMRMLNode* node) const
83+
{
84+
if (!node)
85+
{
86+
return false;
87+
}
88+
89+
return this->IsPlacing() && (this->GetActivePlaceNodeID() == std::string(node->GetID()));
90+
}
91+
92+
bool vtkMRMLLayerDMSelectionObserver::IsPlacing() const
93+
{
94+
if (!this->m_interactionNode)
95+
{
96+
return false;
97+
}
98+
99+
return this->m_interactionNode->GetCurrentInteractionMode() == vtkMRMLInteractionNode::Place;
100+
}
101+
102+
void vtkMRMLLayerDMSelectionObserver::StartPlace(vtkMRMLNode* node, bool isPersistent)
103+
{
104+
if (!node || !this->m_interactionNode || !this->m_selectionNode)
105+
{
106+
return;
107+
}
108+
109+
{
110+
vtkMRMLLayerDMObjectEventObserver::UpdateGuard guard(m_obs);
111+
this->m_selectionNode->SetActivePlaceNodeID(node->GetID());
112+
this->m_interactionNode->SetCurrentInteractionMode(vtkMRMLInteractionNode::Place);
113+
this->m_interactionNode->SetPlaceModePersistence(isPersistent);
114+
}
115+
this->Modified();
116+
}
117+
118+
void vtkMRMLLayerDMSelectionObserver::StopPlace() const
119+
{
120+
this->SetInteractionMode(vtkMRMLInteractionNode::ViewTransform);
121+
}
122+
123+
std::string vtkMRMLLayerDMSelectionObserver::GetActivePlaceNodeID() const
124+
{
125+
if (!this->m_selectionNode)
126+
{
127+
return "";
128+
}
129+
return this->m_selectionNode->GetActivePlaceNodeID();
130+
}
131+
132+
void vtkMRMLLayerDMSelectionObserver::SetInteractionMode(int interactionMode) const
133+
{
134+
if (!m_interactionNode)
135+
{
136+
return;
137+
}
138+
m_interactionNode->SetCurrentInteractionMode(interactionMode);
139+
}
140+
141+
int vtkMRMLLayerDMSelectionObserver::GetCurrentInteractionMode() const
142+
{
143+
if (!this->m_interactionNode)
144+
{
145+
return 0;
146+
}
147+
return this->m_interactionNode->GetCurrentInteractionMode();
148+
}
149+
150+
bool vtkMRMLLayerDMSelectionObserver::GetPlaceModePersistence() const
151+
{
152+
if (!m_interactionNode)
153+
{
154+
return false;
155+
}
156+
return m_interactionNode->GetPlaceModePersistence();
157+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#pragma once
2+
3+
// LayerDM includes
4+
#include "vtkSlicerLayerDMModuleMRMLExport.h"
5+
6+
// VTK includes
7+
#include <vtkObject.h>
8+
#include <vtkSmartPointer.h>
9+
#include <vtkWeakPointer.h>
10+
11+
class vtkMRMLInteractionNode;
12+
class vtkMRMLNode;
13+
class vtkMRMLScene;
14+
class vtkMRMLSelectionNode;
15+
class vtkMRMLLayerDMObjectEventObserver;
16+
class vtkMRMLApplicationLogic;
17+
18+
/// Helper class to observe changes to the interaction / selection singleton pairs.
19+
/// When either selection or interaction change, triggers a modified event.
20+
///
21+
/// Provides helper methods to check if a given node is currently in place mode.
22+
class VTK_SLICER_LAYERDM_MODULE_MRML_EXPORT vtkMRMLLayerDMSelectionObserver : public vtkObject
23+
{
24+
public:
25+
static vtkMRMLLayerDMSelectionObserver* New();
26+
vtkTypeMacro(vtkMRMLLayerDMSelectionObserver, vtkObject);
27+
28+
/// @{
29+
/// \brief Updates selection and interaction nodes from the input scene
30+
/// Uses the singleton instances defined in the scene.
31+
/// For finer granularity, use the direct setters.
32+
void SetScene(vtkMRMLScene* scene);
33+
void UpdateNodesFromScene(vtkMRMLScene* scene);
34+
/// @}
35+
36+
/// \brief Updates selection and interaction nodes from the input application logic
37+
/// Doesn't store the application logic instance.
38+
void UpdateNodesFromApplicationLogic(vtkMRMLApplicationLogic* logic);
39+
40+
bool SetInteractionNode(vtkMRMLInteractionNode* interactionNode);
41+
vtkMRMLInteractionNode* GetInteractionNode() const;
42+
43+
bool SetSelectionNode(vtkMRMLSelectionNode* selectionNode);
44+
vtkMRMLSelectionNode* GetSelectionNode() const;
45+
46+
/// \returns true if the interaction is in place mode and selection active node is the input mrml node
47+
bool IsPlacing(vtkMRMLNode* node) const;
48+
49+
/// \returns true if the interaction is in place mode
50+
bool IsPlacing() const;
51+
52+
/// \brief Starts placing the input node (selection to node ID + interaction in place mode)
53+
void StartPlace(vtkMRMLNode* node, bool isPersistent);
54+
55+
/// \brief Sets the interaction mode to view.
56+
void StopPlace() const;
57+
58+
std::string GetActivePlaceNodeID() const;
59+
void SetInteractionMode(int interactionMode) const;
60+
int GetCurrentInteractionMode() const;
61+
62+
/// \returns true if currently placing and in persistent mode.
63+
bool GetPlaceModePersistence() const;
64+
65+
protected:
66+
vtkMRMLLayerDMSelectionObserver();
67+
~vtkMRMLLayerDMSelectionObserver() override;
68+
vtkMRMLLayerDMSelectionObserver(const vtkMRMLLayerDMSelectionObserver&) = delete;
69+
void operator=(const vtkMRMLLayerDMSelectionObserver&) = delete;
70+
71+
private:
72+
vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver> m_obs;
73+
vtkWeakPointer<vtkMRMLScene> m_scene;
74+
vtkWeakPointer<vtkMRMLInteractionNode> m_interactionNode;
75+
vtkWeakPointer<vtkMRMLSelectionNode> m_selectionNode;
76+
};

LayerDM/Testing/Python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(EXTENSION_TEST_PYTHON_SCRIPTS
99
ObjectEventObserverScriptedTest.py
1010
PipelineFactoryTest.py
1111
PipelineManagerTest.py
12+
SelectionTest.py
1213
)
1314

1415
set(EXTENSION_TEST_PYTHON_RESOURCES

0 commit comments

Comments
 (0)