Clickity Click

May 31, 2016


In my last blog post I had started on building the UI with a button element. The problem with the one I had initially built was that it was in 3D. While 3D is cool, it’s not very useful when it comes to buttons that are 2D, i.e. you don’t want your button to reduce to a line when you rotate the scene by 90 degrees.

And so, I learnt how to build 2D overlays. Now an actor in VTK can be of two types - a 3D actor and a 2D actor. For an overlay button, we want a 2D actor, since it stays stuck on the screen and doesn’t move as you move the screen. Next was to associate a PNG with the button and here’s how you can do so:

png = vtk.vtkPNGReader()
png.SetFileName(icon_fname)
png.Update()

# Convert the image to a polydata
imageDataGeometryFilter = vtk.vtkImageDataGeometryFilter()
imageDataGeometryFilter.SetInputConnection(png.GetOutputPort())
imageDataGeometryFilter.Update()

mapper = vtk.vtkPolyDataMapper2D()
mapper.SetInputConnection(icon.GetOutputPort())

button = vtk.vtkTexturedActor2D()
button.SetMapper(mapper)

The button is the 2D actor you need. Next, we need to capture the click for the button. For this, VTK has a prop picker which can be used in the interactorStyle to get which prop was clicked. Here’s how you do it:

# Define the picker
picker = vtk.vtkPropPicker()
# This gets the position of the click
picker.Pick(click_pos[0], click_pos[1], 0, self.renderer)
# GetViewProp and GetActor2D both can be used alternatively to get the actor2d at the position of the click.
actor_2d = self.picker.GetViewProp() # actor = picker.GetActor2D()
if actor_2d is not None:
    actor_2d.InvokeEvent(evt)
# If there is no actor2d at the click position, we see if there is a 3D actor. 
# We give more preference to the overlay buttons
else:
    actor_3d = self.picker.GetProp3D()
    if actor_3d is not None:
        actor_3d.InvokeEvent(evt)
    else:
        print("No actor at this position")

And so, the button clicks have been captured using vanilla VTK, without using a button widget which gives us slightly less control.

The result, this.

A button overlay

I have built a button class with loads of features - button change on event, ability to add callbacks on events etc. These have been partially documented, the complete documentation will be done later.

Next Steps

The next UI element I’ll be building is a text box. Let’s see how it goes.