[pitivi: 2/8] ui/timeline: move to the next/prev keyframe with 'E'/'R' keys or menu buttons.
- From: Edward Hervey <edwardrv src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi: 2/8] ui/timeline: move to the next/prev keyframe with 'E'/'R' keys or menu buttons.
- Date: Wed, 22 Sep 2010 09:43:52 +0000 (UTC)
commit efa26eb0eec9104a137870a59bdb8905d2c519ff
Author: Luis de Bethencourt <luis debethencourt com>
Date: Mon Sep 20 19:20:53 2010 +0200
ui/timeline: move to the next/prev keyframe with 'E'/'R' keys or menu buttons.
pitivi/timeline/timeline.py | 55 +++++++++++++++++++++++++++
pitivi/ui/timeline.py | 29 ++++++++++++++-
tests/test_timeline.py | 87 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 170 insertions(+), 1 deletions(-)
---
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index e16d7b0..48f938f 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -1954,3 +1954,58 @@ class Timeline(Signallable, Loggable):
break
return objects
+ def getPrevKeyframe(self, time):
+ tl_objs = []
+
+ # Exclude objects that start after current position.
+ for obj in self.timeline_objects:
+ tl_objs.append(obj)
+ if obj.start > time:
+ break
+
+ keyframe_positions = self._getKeyframePositions(tl_objs)
+ for n in range(len(keyframe_positions) -1, -1, -1):
+ if keyframe_positions[n] < time:
+ return keyframe_positions[n]
+ return None
+
+ def getNextKeyframe(self, time):
+ tl_objs = []
+
+ # Include from first object whose end is after the current
+ # position onward.
+ for obj in self.timeline_objects:
+ if (obj.start + obj.duration) > time:
+ n = self.timeline_objects.index(obj)
+ tl_objs.extend(self.timeline_objects[n:])
+ break
+
+ keyframe_positions = self._getKeyframePositions(tl_objs)
+ for n in range(0, len(keyframe_positions)):
+ if keyframe_positions[n] > time:
+ return keyframe_positions[n]
+
+ return None
+
+ def _getKeyframePositions(self, timeline_objects):
+ keyframe_positions = set([])
+ for tl_obj in timeline_objects:
+ first_track = True
+ for track_obj in tl_obj.track_objects:
+ start = track_obj.start
+ in_point = track_obj.in_point
+ if first_track:
+ keyframe_positions.add(start)
+ keyframe_positions.add(start + track_obj.duration)
+ first_track = False
+
+ interpolators = track_obj.getInterpolators()
+ for value in interpolators:
+ interpolator = track_obj.getInterpolator(value)
+ keyframes = interpolator.getInteriorKeyframes()
+ for kf in keyframes:
+ position_in_obj = kf.getTime() + start - in_point
+ keyframe_positions.add(position_in_obj)
+ keyframe_positions = list(keyframe_positions)
+ keyframe_positions.sort()
+ return keyframe_positions
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index 1a6a8ab..6b8ab2b 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -47,6 +47,8 @@ from pitivi.ui.curve import Curve
DELETE = _("Delete Selected")
SPLIT = _("Split clip at playhead position")
KEYFRAME = _("Add a keyframe")
+PREVFRAME = _("Move to the previous keyframe")
+NEXTFRAME = _("Move to the next keyframe")
ZOOM_IN = _("Zoom In")
ZOOM_OUT = _("Zoom Out")
UNLINK = _("Break links between clips")
@@ -75,6 +77,9 @@ ui = '''
<menuitem action="UnlinkObj" />
<menuitem action="GroupObj" />
<menuitem action="UngroupObj" />
+ <separator />
+ <menuitem action="Prevframe" />
+ <menuitem action="Nextframe" />
</placeholder>
</menu>
</menubar>
@@ -311,6 +316,10 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.split),
("Keyframe", "pitivi-keyframe", _("Add a keyframe"), "K", KEYFRAME,
self.keyframe),
+ ("Prevframe", "pitivi-prevframe", _("_Prevframe"), "E", PREVFRAME,
+ self.prevframe),
+ ("Nextframe", "pitivi-nextframe", _("_Nextframe"), "R", NEXTFRAME,
+ self.nextframe),
)
actiongroup = gtk.ActionGroup("timelinepermanent")
@@ -327,6 +336,8 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.delete_action = actiongroup.get_action("DeleteObj")
self.split_action = actiongroup.get_action("Split")
self.keyframe_action = actiongroup.get_action("Keyframe")
+ self.prevframe_action = actiongroup.get_action("Prevframe")
+ self.nextframe_action = actiongroup.get_action("Nextframe")
self.ui_manager.insert_action_group(actiongroup, -1)
@@ -668,7 +679,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
for obj in selected:
keyframe_exists = False
- position_in_obj = timeline_position - obj.start
+ position_in_obj = (timeline_position - obj.start) + obj.in_point
interpolators = obj.getInterpolators()
for value in interpolators:
interpolator = obj.getInterpolator(value)
@@ -683,3 +694,19 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.app.action_log.begin("add volume point")
interpolator.newKeyframe(position_in_obj)
self.app.action_log.commit()
+
+ def prevframe(self, action):
+ timeline_position = self._position
+
+ prev_kf = self.timeline.getPrevKeyframe(timeline_position)
+ if prev_kf != None:
+ self._seeker.seek(prev_kf)
+ self.timelinePositionChanged(prev_kf)
+
+ def nextframe(self, action):
+ timeline_position = self._position
+
+ next_kf = self.timeline.getNextKeyframe(timeline_position)
+ if next_kf:
+ self._seeker.seek(next_kf)
+ self.timelinePositionChanged(next_kf)
diff --git a/tests/test_timeline.py b/tests/test_timeline.py
index 1abeabf..8cf956a 100644
--- a/tests/test_timeline.py
+++ b/tests/test_timeline.py
@@ -629,6 +629,93 @@ class TestTimeline(TestCase):
min_priority=3, max_priority=4)
self.failUnlessEqual(result, tmp_obj_list)
+ def testGetKeyframe(self):
+ timeline_object0 = self.makeTimelineObject()
+ timeline_object1 = self.makeTimelineObject()
+ timeline_object3 = self.makeTimelineObject()
+
+ timeline_object0.start = 0 * gst.SECOND
+ timeline_object0.duration = 1 * gst.SECOND
+ timeline_object0.priority = 0
+
+ timeline_object1.start = 1 * gst.SECOND
+ timeline_object1.duration = 5 * gst.SECOND
+ timeline_object1.priority = 1
+
+ timeline_object3.start = 15 * gst.SECOND
+ timeline_object3.duration = 5 * gst.SECOND
+ timeline_object3.priority = 2
+
+ factory = AudioTestSourceFactory()
+ stream = AudioStream(gst.Caps("audio/x-raw-int"))
+ track_object = SourceTrackObject(factory, stream)
+ self.track1.addTrackObject(track_object)
+ timeline_object2 = TimelineObject(factory)
+ timeline_object2.addTrackObject(track_object)
+ self.timeline.addTimelineObject(timeline_object2)
+ timeline_object2.start = 3 * gst.SECOND
+ timeline_object2.duration = 10 * gst.SECOND
+ timeline_object2.priority = 1
+
+ interpolator = track_object.getInterpolator("volume")
+ keyframe_position = 7 * gst.SECOND - timeline_object2.start
+ interpolator.newKeyframe(keyframe_position, 0.0, "mode")
+
+ timeline = self.timeline
+
+ time1 = 0
+ time2 = 0.5 * gst.SECOND
+ time3 = 2 * gst.SECOND
+ time4 = 6.5 * gst.SECOND
+ time5 = 10 * gst.SECOND
+ time6 = 14 * gst.SECOND
+ time7 = 25 * gst.SECOND
+
+ result = timeline.getPrevKeyframe(time1)
+ self.failUnlessEqual(result, None)
+ result = timeline.getPrevKeyframe(time2)
+ self.failUnlessEqual(result, 0 * gst.SECOND)
+ result = timeline.getPrevKeyframe(time3)
+ self.failUnlessEqual(result, 1 * gst.SECOND)
+ result = timeline.getPrevKeyframe(time4)
+ self.failUnlessEqual(result, 6 * gst.SECOND)
+ result = timeline.getPrevKeyframe(time5)
+ self.failUnlessEqual(result, 7 * gst.SECOND)
+ result = timeline.getPrevKeyframe(time6)
+ self.failUnlessEqual(result, 13 * gst.SECOND)
+ result = timeline.getPrevKeyframe(time7)
+ self.failUnlessEqual(result, 20 * gst.SECOND)
+
+ result = timeline.getNextKeyframe(time1)
+ self.failUnlessEqual(result, 1 * gst.SECOND)
+ result = timeline.getNextKeyframe(time2)
+ self.failUnlessEqual(result, 1 * gst.SECOND)
+ result = timeline.getNextKeyframe(time3)
+ self.failUnlessEqual(result, 3 * gst.SECOND)
+ result = timeline.getNextKeyframe(time4)
+ self.failUnlessEqual(result, 7 * gst.SECOND)
+ result = timeline.getNextKeyframe(time5)
+ self.failUnlessEqual(result, 13 * gst.SECOND)
+ result = timeline.getNextKeyframe(time6)
+ self.failUnlessEqual(result, 15 * gst.SECOND)
+ result = timeline.getNextKeyframe(time7)
+ self.failUnlessEqual(result, None)
+
+ other_object2 = timeline_object2.split(8 * gst.SECOND)
+ timeline_object2.start = 5 * gst.SECOND
+ other_object2.start = 7 * gst.SECOND
+ time1 = 7 * gst.SECOND
+ time2 = 10 * gst.SECOND
+ result = timeline.getNextKeyframe(time1)
+ self.failUnlessEqual(result, 9 * gst.SECOND)
+ result = timeline.getNextKeyframe(time2)
+ self.failUnlessEqual(result, 12 * gst.SECOND)
+
+ position = 8.5 * gst.SECOND
+ interpolator = other_object2.track_objects[0].getInterpolator("volume")
+ interpolator.newKeyframe(position)
+ result = timeline.getNextKeyframe(time2)
+ self.failUnlessEqual(result, 10.5 * gst.SECOND)
class TestLink(TestCase):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]