Disable interaction with camera

Hello everyone,
So I’m developping a module in python and at some point i need to move the camera around. For that I need to disable all the interaction that moves the camera around in the 3D view.
My solution for now is to reach the interactor and to delete it until the module does not need it anymore. I use those few lines to achieve it :

#Copy original interactor
self.interactorStyle = slicer.app.layoutManager().threeDWidget(0).threeDView().interactorStyle()
self.interactor = self.interactorStyle.GetInteractor()
#Delete the interactor
self.interactorStyle.SetInteractor(None)
#Reset the interactor
self.interactorStyle.SetInteractor(self.interactor)

It works for now but i’m afraid that it could interfere with other modules or cause problem with slicer directly.
I tried to find some other functions on vtkInteractorStyle but none seemed to work as i wanted.

Is there a way to achieve what i did directly in slicer or with a function i would have missed ?

Thank you.
Eloi

There is a proper interface to customize what mouse gestures you enable on every view. Here is an example in the script repository for slice views that works the same way for 3D views with small adjustments: https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Disable_certain_user_interactions_in_slice_views

Yes, i saw this example and tried to adapt it but i did not find a documentation to use SetActionEnabled().

If you search for “SetActionEnabled” in Slicer’s source code or API documentation to find the usable values:

Sorry to re-open this topic, but I don’t undestand the proposed solution since vtkMRMLThreeDViewInteractorStyle has no SetActionEnabled function.
Also, vtkMRMLThreeDViewInteractorStyle::EnabledOff() and vtkMRMLThreeDViewInteractorStyle::Off() do not deactivate interaction with the 3D scene.
So, how does one disable interaction in a 3D view ?

SetActionEnabled was added at the time when keyboard&mouse gestures were hardcoded and we needed a way to disable some. Now you can add/remove/edit all keyboard&mouse gestures - see for example here. SetActionEnabled method is only kept for backward compatibility, but I would not recommend using them anymore.

I see, but if I were to follow this example, disabling all interaction would require to set all events of the camerawidget to vtk.vtkWidgetEvent.NoEvent, right ? Given the number of interactions possible in vtkCommand, this will be quite long (unless I could loop on it). Isn’t there a simpler way ?

In general, it is not expected that a module disables all other modules. You are always expected to know what features you disable and why. You might be able to implement some simpler hacks, such as adding an observer to the interactor for all interaction events with very high priority that consumes all the events (as it is done in Segment Editor, which was implemented before the widget infrastructure was in place).

Why do you need to disable all interactions?

I’m displaying a frustum in 3D from a very specific point of view, so I don’t want the user to be able to move the camera and change that point of view.
Also, I’m using parallel projection for the camera and mouse-wheel zooming turns it off for some reason (if it’s a bug I’ll open a new separate ticket).

I’m displaying a frustum in 3D from a very specific point of view, so I don’t want the user to be able to move the camera and change that point of view.

Then disabling camera translation & rotation may make sense. You may still want to allow right-click menu, etc. so it makes sense not to disable all interactions.

Mouse wheel should not change camera projection, so it that happens then it is a bug. I tried this and for me the view is zoomed in/out with mouse wheel correctly (without changing projection mode).

Ok, I’ll try to find a way to disable only the necessary.

I’m able to reproduce the bug with:

layoutManager = slicer.app.layoutManager()
view = layoutManager.threeDWidget(0).threeDView()
renderWindow = view.renderWindow()
renderer = renderWindow.GetRenderers().GetItemAsObject(0)
camera = renderer.GetActiveCamera()
camera.ParallelProjectionOn()

I see, this is not a bug, but it is due to that camera projection mode is defined in vtkMRMLViewNode. If you change it in the camera VTK object then the view node will restore it to the stored value at the next update. I agree that this can be unexpected and it is probably like this due to historical reasons. You could file an enhancement request to change this (i.e., only store projection mode in the camera node, not in the view node).

1 Like

The enhancement request has been posted here.

1 Like