Skip to content

Commit 5bbb4ae

Browse files
ENH: Add Object Event Observer Scripted
- Add vtkMRMLLayerDMObjectEventObserverScripted helper to update observers for vtk objects in Python. - Factorize python binding logic to vtkMRMLLayerDMPythonUtil - Rename vtkObjectEventObserver for namespace consistency
1 parent 165e189 commit 5bbb4ae

16 files changed

Lines changed: 484 additions & 225 deletions

LayerDM/MRMLDM/CMakeLists.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ set(${KIT}_SRCS
2727
vtkMRMLLayerDMInteractionLogic.h
2828
vtkMRMLLayerDMLayerManager.cxx
2929
vtkMRMLLayerDMLayerManager.h
30+
vtkMRMLLayerDMObjectEventObserver.cxx
31+
vtkMRMLLayerDMObjectEventObserver.h
3032
vtkMRMLLayerDMPipelineCallbackCreator.cxx
3133
vtkMRMLLayerDMPipelineCallbackCreator.h
3234
vtkMRMLLayerDMPipelineCreateHelper.h
@@ -39,14 +41,16 @@ set(${KIT}_SRCS
3941
vtkMRMLLayerDMPipelineManager.cxx
4042
vtkMRMLLayerDMPipelineManager.h
4143
vtkMRMLLayerDisplayableManager.h
42-
vtkObjectEventObserver.cxx
43-
vtkObjectEventObserver.h
4444
)
4545

4646
if (VTK_WRAP_PYTHON)
4747
list(APPEND ${KIT}_SRCS
48+
vtkMRMLLayerDMObjectEventObserverScripted.cxx
49+
vtkMRMLLayerDMObjectEventObserverScripted.h
4850
vtkMRMLLayerDMPipelineScriptedCreator.cxx
4951
vtkMRMLLayerDMPipelineScriptedCreator.h
52+
vtkMRMLLayerDMPythonUtil.cxx
53+
vtkMRMLLayerDMPythonUtil.h
5054
vtkMRMLLayerDMScriptedPipelineBridge.cxx
5155
vtkMRMLLayerDMScriptedPipelineBridge.h
5256
)

LayerDM/MRMLDM/vtkMRMLLayerDMCameraSynchronizer.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include "vtkMRMLLayerDMCameraSynchronizer.h"
22

33
// Layer DM includes
4-
#include "vtkObjectEventObserver.h"
4+
#include "vtkMRMLLayerDMObjectEventObserver.h"
55

66
// Slicer includes
77
#include "vtkMRMLAbstractViewNode.h"
@@ -28,7 +28,7 @@ class CameraSynchronizeStrategy
2828

2929
protected:
3030
vtkSmartPointer<vtkCamera> m_camera;
31-
vtkNew<vtkObjectEventObserver> m_eventObserver;
31+
vtkNew<vtkMRMLLayerDMObjectEventObserver> m_eventObserver;
3232
};
3333

3434
class DefaultCameraSynchronizeStrategy : public CameraSynchronizeStrategy

LayerDM/MRMLDM/vtkObjectEventObserver.cxx renamed to LayerDM/MRMLDM/vtkMRMLLayerDMObjectEventObserver.cxx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
#include "vtkObjectEventObserver.h"
1+
#include "vtkMRMLLayerDMObjectEventObserver.h"
22

33
// VTK includes
44
#include <vtkCallbackCommand.h>
55
#include <vtkObjectFactory.h>
66

7-
vtkStandardNewMacro(vtkObjectEventObserver);
7+
vtkStandardNewMacro(vtkMRMLLayerDMObjectEventObserver);
88

99
template <class... Ts>
1010
struct Overloaded : Ts...
@@ -15,14 +15,14 @@ struct Overloaded : Ts...
1515
template <class... Ts>
1616
Overloaded(Ts...) -> Overloaded<Ts...>;
1717

18-
vtkObjectEventObserver::vtkObjectEventObserver()
18+
vtkMRMLLayerDMObjectEventObserver::vtkMRMLLayerDMObjectEventObserver()
1919
: m_updateCommand(vtkSmartPointer<vtkCallbackCommand>::New())
2020
{
2121
this->m_updateCommand->SetClientData(this);
2222
this->m_updateCommand->SetCallback(
2323
[](vtkObject* caller, unsigned long eid, void* clientData, void* callData)
2424
{
25-
auto client = static_cast<vtkObjectEventObserver*>(clientData);
25+
auto client = static_cast<vtkMRMLLayerDMObjectEventObserver*>(clientData);
2626
try
2727
{
2828
// Dispatch to callback depending on current std variant content
@@ -38,7 +38,7 @@ vtkObjectEventObserver::vtkObjectEventObserver()
3838
});
3939
}
4040

41-
vtkObjectEventObserver::~vtkObjectEventObserver()
41+
vtkMRMLLayerDMObjectEventObserver::~vtkMRMLLayerDMObjectEventObserver()
4242
{
4343
for (const auto& obs : m_obsMap)
4444
{
@@ -52,12 +52,12 @@ vtkObjectEventObserver::~vtkObjectEventObserver()
5252
}
5353
}
5454

55-
bool vtkObjectEventObserver::UpdateObserver(vtkObject* prevObj, vtkObject* obj, unsigned long event)
55+
bool vtkMRMLLayerDMObjectEventObserver::UpdateObserver(vtkObject* prevObj, vtkObject* obj, unsigned long event)
5656
{
5757
return this->UpdateObserver(prevObj, obj, std::vector<unsigned long>{ event });
5858
}
5959

60-
bool vtkObjectEventObserver::UpdateObserver(vtkObject* prevObj, vtkObject* obj, const std::vector<unsigned long>& events)
60+
bool vtkMRMLLayerDMObjectEventObserver::UpdateObserver(vtkObject* prevObj, vtkObject* obj, const std::vector<unsigned long>& events)
6161
{
6262
if (prevObj == obj)
6363
{
@@ -72,22 +72,22 @@ bool vtkObjectEventObserver::UpdateObserver(vtkObject* prevObj, vtkObject* obj,
7272
return true;
7373
}
7474

75-
void vtkObjectEventObserver::SetUpdateCallback(const std::function<void(vtkObject* node)>& callback)
75+
void vtkMRMLLayerDMObjectEventObserver::SetUpdateCallback(const std::function<void(vtkObject* node)>& callback)
7676
{
7777
this->m_callback = callback;
7878
}
7979

80-
void vtkObjectEventObserver::SetUpdateCallback(const std::function<void(vtkObject* node, unsigned long eventId)>& callback)
80+
void vtkMRMLLayerDMObjectEventObserver::SetUpdateCallback(const std::function<void(vtkObject* node, unsigned long eventId)>& callback)
8181
{
8282
this->m_callback = callback;
8383
}
8484

85-
void vtkObjectEventObserver::SetUpdateCallback(const std::function<void(vtkObject* node, unsigned long eventId, void* callData)>& callback)
85+
void vtkMRMLLayerDMObjectEventObserver::SetUpdateCallback(const std::function<void(vtkObject* node, unsigned long eventId, void* callData)>& callback)
8686
{
8787
this->m_callback = callback;
8888
}
8989

90-
void vtkObjectEventObserver::AddObserver(vtkObject* node, unsigned long event)
90+
void vtkMRMLLayerDMObjectEventObserver::AddObserver(vtkObject* node, unsigned long event)
9191
{
9292
if (!node)
9393
{
@@ -107,7 +107,7 @@ void vtkObjectEventObserver::AddObserver(vtkObject* node, unsigned long event)
107107
this->m_obsMap[node].insert(node->AddObserver(event, this->m_updateCommand));
108108
}
109109

110-
void vtkObjectEventObserver::RemoveObserver(vtkObject* node)
110+
void vtkMRMLLayerDMObjectEventObserver::RemoveObserver(vtkObject* node)
111111
{
112112
if (!node || this->m_obsMap.find(node) == std::end(this->m_obsMap))
113113
{

LayerDM/MRMLDM/vtkObjectEventObserver.h renamed to LayerDM/MRMLDM/vtkMRMLLayerDMObjectEventObserver.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ class vtkCallbackCommand;
2121
/// Can observe multiple objects and multiple events per object.
2222
///
2323
/// Depending on the callback used, event id and call data can either be forwarded or ignored.
24-
class VTK_SLICER_LAYERDM_MODULE_MRMLDISPLAYABLEMANAGER_EXPORT vtkObjectEventObserver : public vtkObject
24+
class VTK_SLICER_LAYERDM_MODULE_MRMLDISPLAYABLEMANAGER_EXPORT vtkMRMLLayerDMObjectEventObserver : public vtkObject
2525
{
2626
public:
27-
static vtkObjectEventObserver* New();
28-
vtkTypeMacro(vtkObjectEventObserver, vtkObject);
27+
static vtkMRMLLayerDMObjectEventObserver* New();
28+
vtkTypeMacro(vtkMRMLLayerDMObjectEventObserver, vtkObject);
2929

3030
/// @{
3131
/// Remove previous monitored events from \param prevObj and observe events from the \param obj
@@ -49,8 +49,8 @@ class VTK_SLICER_LAYERDM_MODULE_MRMLDISPLAYABLEMANAGER_EXPORT vtkObjectEventObse
4949
/// @}
5050

5151
protected:
52-
vtkObjectEventObserver();
53-
~vtkObjectEventObserver() override;
52+
vtkMRMLLayerDMObjectEventObserver();
53+
~vtkMRMLLayerDMObjectEventObserver() override;
5454

5555
private:
5656
void AddObserver(vtkObject* obj, unsigned long event);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "vtkMRMLLayerDMObjectEventObserverScripted.h"
2+
3+
#include "vtkMRMLLayerDMPythonUtil.h"
4+
#include <vtkObjectFactory.h>
5+
6+
vtkStandardNewMacro(vtkMRMLLayerDMObjectEventObserverScripted);
7+
8+
vtkMRMLLayerDMObjectEventObserverScripted::vtkMRMLLayerDMObjectEventObserverScripted()
9+
: m_object(nullptr)
10+
{
11+
this->SetUpdateCallback(
12+
[this](vtkObject* node, unsigned long eventId, void* callData) -> void
13+
{
14+
if (!Py_IsInitialized())
15+
{
16+
return;
17+
}
18+
19+
vtkPythonScopeGilEnsurer gilEnsurer;
20+
vtkMRMLLayerDMPythonUtil::CallPythonObject(this->m_object, vtkMRMLLayerDMPythonUtil::ToPyArgs(node, eventId, callData));
21+
});
22+
}
23+
24+
vtkMRMLLayerDMObjectEventObserverScripted::~vtkMRMLLayerDMObjectEventObserverScripted()
25+
{
26+
vtkMRMLLayerDMPythonUtil::DeletePythonObject(&this->m_object);
27+
}
28+
29+
void vtkMRMLLayerDMObjectEventObserverScripted::SetPythonCallback(PyObject* object)
30+
{
31+
vtkMRMLLayerDMPythonUtil::SetPythonObject(&this->m_object, object);
32+
}
33+
34+
PyObject* vtkMRMLLayerDMObjectEventObserverScripted::CastCallData(PyObject* object, int vtkType)
35+
{
36+
return vtkMRMLLayerDMPythonUtil::CastCallData(object, vtkType);
37+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
#include "vtkSlicerLayerDMModuleMRMLDisplayableManagerExport.h"
4+
5+
#include "vtkMRMLLayerDMObjectEventObserver.h"
6+
7+
// VTK includes
8+
#include <vtkPython.h>
9+
#include <vtkSmartPyObject.h>
10+
11+
class vtkCallbackCommand;
12+
13+
/// Python lambda implementation of \sa vtkMRMLLayerDMObjectEventObserver
14+
/// Delegates full callback to underlying Python callable object.
15+
class VTK_SLICER_LAYERDM_MODULE_MRMLDISPLAYABLEMANAGER_EXPORT vtkMRMLLayerDMObjectEventObserverScripted : public vtkMRMLLayerDMObjectEventObserver
16+
{
17+
public:
18+
static vtkMRMLLayerDMObjectEventObserverScripted* New();
19+
vtkTypeMacro(vtkMRMLLayerDMObjectEventObserverScripted, vtkMRMLLayerDMObjectEventObserver);
20+
21+
/// \brief Sets the Python callable object to be invoked on events.
22+
///
23+
/// The provided Python object should be callable (e.g., a function, lambda,
24+
/// or an object with a __call__ method). This callable will be invoked
25+
/// whenever the observed event is triggered.
26+
///
27+
/// The python callable will be invoked with the following args:
28+
/// (vtkObject* node, unsigned long eventId, void* callData)
29+
///
30+
/// If callData is not nullptr, the callData can be converted to the right
31+
/// Python type using the \see CastCallData method.
32+
void SetPythonCallback(PyObject* object);
33+
34+
/// \brief Cast call data to appropriate Python type based on VTK type
35+
/// \param object Python object to cast
36+
/// \param vtkType VTK type identifier to cast to
37+
/// \return PyObject* Casted Python object
38+
static PyObject* CastCallData(PyObject* object, int vtkType);
39+
40+
protected:
41+
vtkMRMLLayerDMObjectEventObserverScripted();
42+
~vtkMRMLLayerDMObjectEventObserverScripted() override;
43+
44+
private:
45+
PyObject* m_object;
46+
};

LayerDM/MRMLDM/vtkMRMLLayerDMPipelineI.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "vtkMRMLAbstractWidget.h"
55
#include "vtkMRMLLayerDMPipelineManager.h"
66
#include "vtkMRMLScene.h"
7-
#include "vtkObjectEventObserver.h"
7+
#include "vtkMRMLLayerDMObjectEventObserver.h"
88

99
// VTK includes
1010
#include <vtkObjectFactory.h>
@@ -168,7 +168,7 @@ vtkMRMLLayerDMPipelineI::vtkMRMLLayerDMPipelineI()
168168
, m_displayNode{ nullptr }
169169
, m_renderer{ nullptr }
170170
, m_isResetDisplayBlocked{ false }
171-
, m_obs(vtkSmartPointer<vtkObjectEventObserver>::New())
171+
, m_obs(vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver>::New())
172172
, m_pipelineManager(nullptr)
173173
{
174174
this->m_obs->SetUpdateCallback([this](vtkObject* obj, unsigned long eventId, void* callData) { this->OnUpdate(obj, eventId, callData); });

LayerDM/MRMLDM/vtkMRMLLayerDMPipelineI.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class vtkMRMLLayerDMPipelineI;
1616
class vtkMRMLLayerDMPipelineManager;
1717
class vtkMRMLNode;
1818
class vtkMRMLScene;
19-
class vtkObjectEventObserver;
19+
class vtkMRMLLayerDMObjectEventObserver;
2020
class vtkRenderer;
2121

2222
/// \brief Interface for the layered displayable manager pipelines.
@@ -180,7 +180,7 @@ class VTK_SLICER_LAYERDM_MODULE_MRMLDISPLAYABLEMANAGER_EXPORT vtkMRMLLayerDMPipe
180180
vtkWeakPointer<vtkMRMLNode> m_displayNode;
181181
vtkWeakPointer<vtkRenderer> m_renderer;
182182
bool m_isResetDisplayBlocked;
183-
vtkSmartPointer<vtkObjectEventObserver> m_obs;
183+
vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver> m_obs;
184184
vtkWeakPointer<vtkMRMLLayerDMPipelineManager> m_pipelineManager;
185185
vtkWeakPointer<vtkMRMLScene> m_scene;
186186
};

LayerDM/MRMLDM/vtkMRMLLayerDMPipelineManager.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "vtkMRMLLayerDMLayerManager.h"
77
#include "vtkMRMLLayerDMPipelineFactory.h"
88
#include "vtkMRMLLayerDMPipelineI.h"
9-
#include "vtkObjectEventObserver.h"
9+
#include "vtkMRMLLayerDMObjectEventObserver.h"
1010

1111
// Slicer includes
1212
#include "vtkMRMLAbstractViewNode.h"
@@ -178,7 +178,7 @@ vtkMRMLLayerDMPipelineManager::vtkMRMLLayerDMPipelineManager()
178178
, m_layerManager(vtkSmartPointer<vtkMRMLLayerDMLayerManager>::New())
179179
, m_cameraSync(vtkSmartPointer<vtkMRMLLayerDMCameraSynchronizer>::New())
180180
, m_interactionLogic(vtkSmartPointer<vtkMRMLLayerDMInteractionLogic>::New())
181-
, m_eventObs(vtkSmartPointer<vtkObjectEventObserver>::New())
181+
, m_eventObs(vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver>::New())
182182
, m_defaultCamera(vtkSmartPointer<vtkCamera>::New())
183183
, m_viewNode{ nullptr }
184184
, m_scene{ nullptr }

LayerDM/MRMLDM/vtkMRMLLayerDMPipelineManager.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ class vtkMRMLLayerDMPipelineFactory;
2323
class vtkMRMLLayerDMPipelineI;
2424
class vtkMRMLNode;
2525
class vtkMRMLScene;
26-
class vtkObjectEventObserver;
26+
class vtkMRMLLayerDMObjectEventObserver;
2727
class vtkRenderWindow;
2828
class vtkRenderer;
2929

30-
/// @brief Class responsible for handling adding / updating / removing pipelines depending on nodes added / removed /
30+
/// \brief Class responsible for handling adding / updating / removing pipelines depending on nodes added / removed /
3131
/// updated in the 3D Slicer Scene.
3232
///
3333
/// The display manager handles connections to the scene's events.
@@ -131,7 +131,7 @@ class VTK_SLICER_LAYERDM_MODULE_MRMLDISPLAYABLEMANAGER_EXPORT vtkMRMLLayerDMPipe
131131
vtkSmartPointer<vtkMRMLLayerDMLayerManager> m_layerManager;
132132
vtkSmartPointer<vtkMRMLLayerDMCameraSynchronizer> m_cameraSync;
133133
vtkSmartPointer<vtkMRMLLayerDMInteractionLogic> m_interactionLogic;
134-
vtkSmartPointer<vtkObjectEventObserver> m_eventObs;
134+
vtkSmartPointer<vtkMRMLLayerDMObjectEventObserver> m_eventObs;
135135
vtkSmartPointer<vtkCamera> m_defaultCamera;
136136

137137
vtkWeakPointer<vtkMRMLAbstractViewNode> m_viewNode;

0 commit comments

Comments
 (0)