So I made the following minimum example to test the widget in Python, maybe I’m missing something obvious.
The code subclasses vtkPlaybackRepresentation and tests that the widget can access the new overridden functions, I then had to add an observer that then calculates the cursor position and then calls a function depending on the fractional position of the cursor. The inbuilt methods don’t seem to work and I can’t seem to get the bounds of the representation so I guessed the rough ones (super hacky, hate it).
At this point this widget seems about as useful as the textured button, shouldn’t there be an internal method that does all of this in the widget itself?
Looking at the source code it’s definitely there, but maybe the function is no longer used in the Python implementation.
import vtk
class newRepresentation(vtk.vtkPlaybackRepresentation):
def __init__(self):
self.SetShowBorderToOff()
self.ProportionalResizeOn()
self.BuildRepresentation()
self.Modified()
print('Initialised new representation')
# print(self)
def Play(self):
print('Play')
def Stop(self):
print('Stop')
def ForwardOneFrame(self):
print('Forward 1')
def BackwardOneFrame(self):
print('Backward 1')
def JumpToBeginning(self):
print('Jump to Beginning')
def JumpToEnd(self):
print('Jump to End')
def add_playback_widget(render_window_interactor):
# Create the playback widget
playback_widget = vtk.vtkPlaybackWidget()
# Set up the playback widget
playback_widget.SetInteractor(render_window_interactor)
playback_rep = newRepresentation()
playback_widget.SetRepresentation(playback_rep)
playback_widget.PickingManagedOn()
playback_widget.ProcessEventsOn()
playback_widget.SetEnabled(True)
playback_widget.DebugOn()
playback_widget.On()
playback_widget.Modified()
print('Testing overidden functions:')
playback_widget.GetRepresentation().Play()
playback_widget.GetRepresentation().Stop()
playback_widget.GetRepresentation().ForwardOneFrame()
playback_widget.GetRepresentation().BackwardOneFrame()
playback_widget.GetRepresentation().JumpToBeginning()
playback_widget.GetRepresentation().JumpToEnd()
print('End of tests \n')
print(playback_rep, sorted(dir(playback_rep)))
print(playback_widget, sorted(dir(playback_widget)))
return playback_widget
def click_to_function(playback_widget):
x_full, _ = playback_widget.GetInteractor().GetEventPosition()
selection_pos = playback_widget.GetRepresentation().GetSelectionPoint()
widget_bounds = playback_widget.GetRepresentation().GetBounds()
print('Any reason these methods don\'t work?', selection_pos, widget_bounds)
# Hacky workaround to get the fractional position, will break if the widget is moved
window_size = playback_widget.GetInteractor().GetRenderWindow().GetSize()
widget_bounds = [0.1 * window_size[0],0.5 * window_size[0], 0.05 * window_size[1], 0.1 * window_size[1]]
x = (x_full - widget_bounds[0])/(widget_bounds[1]-widget_bounds[0])
# This seems like a dumb way to do things, shouldn't this all be handled internally?
if (x < 0.16667):
playback_widget.GetRepresentation().JumpToBeginning()
elif (x <= 0.333333):
playback_widget.GetRepresentation().BackwardOneFrame()
elif (x <= 0.500000):
playback_widget.GetRepresentation().Stop()
elif (x < 0.666667):
playback_widget.GetRepresentation().Play()
elif (x <= 0.833333):
playback_widget.GetRepresentation().ForwardOneFrame()
elif (x <= 1.00000):
playback_widget.GetRepresentation().JumpToEnd()
return
def playback_callback(widget, event):
print('Current event:', event)
state = widget.GetRepresentation().GetInteractionState()
state_min = widget.GetRepresentation().GetInteractionStateMinValue()
state_max = widget.GetRepresentation().GetInteractionStateMaxValue()
print("Representation state", state, state_min, state_max)
click_to_function(widget)
def main(record_events=False, print_events=True):
# Create a renderer, render window, and interactor
renderer = vtk.vtkRenderer()
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window_interactor = vtk.vtkRenderWindowInteractor()
render_window_interactor.SetRenderWindow(render_window)
render_window_interactor.Initialize()
# Create a sphere
sphere_source = vtk.vtkSphereSource()
sphere_source.SetRadius(5.0)
sphere_source.SetThetaResolution(30)
sphere_source.SetPhiResolution(30)
# Create a mapper
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(sphere_source.GetOutputPort())
# Create an actor
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Add the actor to the scene
renderer.AddActor(actor)
renderer.SetBackground(0, 0, 1)
playback_widget = add_playback_widget(render_window_interactor)
if print_events:
print('Code will show any event that happens to the widget\n')
playback_widget.AddObserver("EndInteractionEvent", playback_callback)
if record_events:
print('Code will store every event that happens in the renderer\n')
recorder = vtk.vtkInteractorEventRecorder()
recorder.SetInteractor(render_window_interactor)
recorder.SetFileName("EventRecording.log")
recorder.SetEnabled(True)
recorder.Record()
# Start the interaction
render_window.Render()
render_window_interactor.Start()
if record_events:
recorder.Stop()
recorder.Off()
print('Done')
if __name__ == "__main__":
main()
The little boxes below the 2nd and 5th icons remain a mystery