[pitivi: 9/10] mainwindow, timeline, viewer: keyboard seeking support



commit c3adbf4d7b2e9ccce8fb30cc6649cc0d8ae69571
Author: Brandon Lewis <brandon_lewis berkeley edu>
Date:   Wed Apr 1 01:03:18 2009 -0700

    mainwindow, timeline, viewer: keyboard seeking support
---
 pitivi/timeline/timeline.py |    5 +++
 pitivi/ui/actions.xml       |    3 --
 pitivi/ui/mainwindow.py     |   47 ++++++++++++++++++++++++++--------
 pitivi/ui/viewer.py         |   59 ++++++++++++++++++------------------------
 4 files changed, 66 insertions(+), 48 deletions(-)

diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index fd9b648..4342cce 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -432,6 +432,11 @@ class TimelineEdges(object):
 
         return start + end_diff, end_diff
 
+    def closest(self, time):
+        closest, diff, index = closest_item(self.edges, time)
+        return self.edges[max(0, index - 2)], self.edges[min(
+            len(self.edges) - 1, index + 1)]
+
 
 class Timeline(object ,Signallable):
     __signals__ = {
diff --git a/pitivi/ui/actions.xml b/pitivi/ui/actions.xml
index 7aacb2d..3e61922 100644
--- a/pitivi/ui/actions.xml
+++ b/pitivi/ui/actions.xml
@@ -44,8 +44,5 @@
   <accelerator action="FullScreenAlternate" />
   <accelerator action="PlayPause" />
   <accelerator action="RenderProject" />
-  <accelerator action="FrameBack" />
-  <accelerator action="FrameForward" />
-  <accelerator action="FastForward" />
   <accelerator action="Loop" />
 </ui>
diff --git a/pitivi/ui/mainwindow.py b/pitivi/ui/mainwindow.py
index 3dc792d..8541cd6 100644
--- a/pitivi/ui/mainwindow.py
+++ b/pitivi/ui/mainwindow.py
@@ -140,6 +140,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
         self.settings = instance.settings
         self.is_fullscreen = self.settings.mainWindowFullScreen
         self.missing_plugins = []
+        self.timelinepos = 0
 
     def load(self):
         """ load the user interface """
@@ -154,6 +155,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
         self.app.current.connect("confirm-overwrite", self._confirmOverwriteCb)
         self.project.pipeline.connect("error", self._pipelineErrorCb)
         self.app.current.sources.connect("file_added", self._sourcesFileAddedCb)
+        self.app.current.connect("settings-changed", self._settingsChangedCb)
 
         self.app.current.connect('missing-plugins',
                 self._projectMissingPluginsCb)
@@ -172,6 +174,8 @@ class PitiviMainWindow(gtk.Window, Loggable):
         self.app.current.timeline.connect('duration-changed',
                 self._timelineDurationChangedCb)
 
+        self.rate = float(1 / self.project.getSettings().videorate)
+
     def showEncodingDialog(self, project, pause=True):
         """
         Shows the L{EncodingDialog} for the given project Timeline.
@@ -246,12 +250,8 @@ class PitiviMainWindow(gtk.Window, Loggable):
             ("View", None, _("_View")),
             ("Rewind", gtk.STOCK_MEDIA_REWIND, None, None, REWIND,
                 self.rewind),
-            ("FrameBack", gtk.STOCK_MEDIA_PREVIOUS, None, None, FRAME_BACK,
-                self.frameBack),
             ("PlayPause", gtk.STOCK_MEDIA_PLAY, None, "space", PLAY,
                 self.playPause),
-            ("FrameForward", gtk.STOCK_MEDIA_NEXT, None, None, FRAME_FORWARD,
-                self.frameForward),
             ("FastForward", gtk.STOCK_MEDIA_FORWARD, None, None, FAST_FORWARD,
                 self.fastForward),
             ("Loop", gtk.STOCK_REFRESH, _("Loop"), None, LOOP,
@@ -289,7 +289,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
                 "ProjectSettings", "Quit", "File", "Edit", "Help", "About",
                 "View", "FullScreen", "FullScreenAlternate", "ImportSources",
                 "ImportSourcesFolder", "PluginManager", "PlayPause",
-                "Project"]:
+                "Project", "FrameForward", "FrameBackward"]:
                 action.set_sensitive(True)
             elif action_name in ["SaveProject", "SaveProjectAs",
                     "NewProject", "OpenProject"]:
@@ -310,6 +310,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
         self.set_geometry_hints(min_width=800, min_height=480)
         self.connect("destroy", self._destroyCb)
         self.connect("configure-event", self._configureCb)
+        self.connect("key-press-event", self._keyPressEventCb)
 
         # main menu & toolbar
         vbox = gtk.VBox(False)
@@ -432,6 +433,9 @@ class PitiviMainWindow(gtk.Window, Loggable):
         #    and not len(self.app.current.timeline.videocomp):
         pass
 
+    def _settingsChangedCb(self, project, settings):
+        self.rate = float(1 / self.project.getSettings().videorate)
+
     def _projectMissingPluginsCb(self, project, uri, detail, message):
         self.missing_plugins.append(uri)
         return self._installPlugins(detail)
@@ -463,6 +467,32 @@ class PitiviMainWindow(gtk.Window, Loggable):
         self._saveWindowSettings()
         self.app.shutdown()
 
+    def _keyPressEventCb(self, unused_widget, event):
+        kv = event.keyval
+        mod = event.get_state()
+        frame = long(self.rate * gst.SECOND)
+        now = self.timelinepos
+
+        if kv == gtk.keysyms.Left:
+            if mod & gtk.gdk.SHIFT_MASK:
+                self.viewer.seekRelative(-gst.SECOND)
+            elif mod & gtk.gdk.CONTROL_MASK:
+                ltime, rtime = self.project.timeline.edges.closest(now)
+                self.viewer.seek(ltime)
+            else:
+                self.viewer.seekRelative(-frame)
+            return True
+        elif kv == gtk.keysyms.Right:
+            if mod & gtk.gdk.SHIFT_MASK:
+                self.viewer.seekRelative(gst.SECOND)
+            elif mod & gtk.gdk.CONTROL_MASK:
+                ltime, rtime = self.project.timeline.edges.closest(now)
+                self.viewer.seek(rtime)
+            else:
+                self.viewer.seekRelative(frame)
+            return True
+        return False
+
     def _saveWindowSettings(self):
         self.settings.mainWindowFullscreen = self.is_fullscreen
         self.settings.mainWindowHPanePosition = self.hpaned.get_position()
@@ -586,18 +616,12 @@ class PitiviMainWindow(gtk.Window, Loggable):
     def rewind(self, unused_action):
         pass
 
-    def frameBack(self, unused_action):
-        pass
-
     def playPause(self, unused_action):
         self.viewer.togglePlayback()
 
     def pause(self, unused_action):
         self.viewer.pause()
 
-    def frameForward(self, unused_action):
-        pass
-
     def fastForward(self, unused_action):
         pass
 
@@ -792,3 +816,4 @@ class PitiviMainWindow(gtk.Window, Loggable):
 
     def _timelinePipelinePositionChangedCb(self, pipeline, position):
         self.timeline.timelinePositionChanged(position)
+        self.timelinepos = position
diff --git a/pitivi/ui/viewer.py b/pitivi/ui/viewer.py
index 9fdbdb6..aa12513 100644
--- a/pitivi/ui/viewer.py
+++ b/pitivi/ui/viewer.py
@@ -326,29 +326,16 @@ class PitiviViewer(gtk.VBox, Loggable):
         value = long(slider.get_value())
         self.info(gst.TIME_ARGS(value))
         if self.moving_slider:
-            self._doSeek(value)
+            self.seek(value)
 
     def _sliderScrollCb(self, unused_slider, event):
-        # calculate new seek position
-        if self.current_frame == -1:
-            # time scrolling, 0.5s forward/backward
-            if event.direction in [gtk.gdk.SCROLL_LEFT, gtk.gdk.SCROLL_DOWN]:
-                seekvalue = max(self.current_time - gst.SECOND / 2, 0)
-            else:
-                seekvalue = min(self.current_time + gst.SECOND / 2, self.pipeline.getDuration())
-            self._doSeek(seekvalue)
+        if event.direction == gtk.gdk.SCROLL_LEFT:
+            amount = -gst.SECOND
         else:
-            # frame scrolling, frame by frame
-            self.info("scroll direction:%s", event.direction)
-            if event.direction in [gtk.gdk.SCROLL_LEFT, gtk.gdk.SCROLL_DOWN]:
-                self.info("scrolling backward")
-                seekvalue = max(self.current_frame - 1, 0)
-            else:
-                self.info("scrolling forward")
-                seekvalue = min(self.current_frame + 1, self.pipeline.getDuration())
-            self._doSeek(seekvalue, gst.FORMAT_DEFAULT)
+            amount = gst.SECOND
+        self.seekRelative(self, amount)
 
-    def _doSeek(self, position, format=gst.FORMAT_TIME):
+    def seek(self, position, format=gst.FORMAT_TIME):
         self.seeker.seek(position, format)
 
     def _seekerSeekCb(self, seeker, position, format):
@@ -396,19 +383,19 @@ class PitiviViewer(gtk.VBox, Loggable):
     ## Control gtk.Button callbacks
 
     def _rewindCb(self, unused_button):
-        self.rewind()
+        raise NotImplementedError
 
     def _backCb(self, unused_button):
-        self.back()
+        self.seekRelative(-gst.SECOND)
 
     def _playButtonCb(self, unused_button, isplaying):
         self.togglePlayback()
 
     def _nextCb(self, unused_button):
-        self.next()
+        self.seekRelative(gst.SECOND)
 
     def _forwardCb(self, unused_button):
-        self.forward()
+        raise NotImplementedError
 
     ## public methods for controlling playback
 
@@ -431,17 +418,21 @@ class PitiviViewer(gtk.VBox, Loggable):
         else:
             self.play()
 
-    def rewind(self):
-        raise NotImplementedError
-
-    def back(self):
-        raise NotImplementedError
-
-    def next(self):
-        raise NotImplementedError
-
-    def forward(self):
-        raise NotImplementedError
+    def seekRelative(self, time):
+        seekvalue = max(0, min(self.current_time + time,
+            self.pipeline.getDuration()))
+        self.seek(seekvalue)
+
+    def frameSeekRelative(self, frame):
+        # FIXME: untested
+        self.info("scroll direction:%s", event.direction)
+        if direction in [gtk.gdk.SCROLL_LEFT, gtk.gdk.SCROLL_DOWN]:
+            self.info("scrolling backward")
+            seekvalue = max(self.current_frame - 1, 0)
+        else:
+            self.info("scrolling forward")
+            seekvalue = min(self.current_frame + 1, self.pipeline.getDuration())
+        self.seek(seekvalue, gst.FORMAT_DEFAULT)
 
     def _posCb(self, unused_pipeline, pos):
         self._newTime(pos)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]