[pitivi/ges: 185/287] timeline: Merge timelinecanvas.py into timeline.py



commit 5f209a8dc2f7b8bafac3cbe40fdb08ae84c42871
Author: Thibault Saunier <thibault saunier collabora com>
Date:   Tue Jan 10 18:14:44 2012 -0300

    timeline: Merge timelinecanvas.py into timeline.py

 pitivi/timeline/Makefile.am       |    1 -
 pitivi/timeline/timeline.py       |  332 +++++++++++++++++++++++++++++++++++-
 pitivi/timeline/timelinecanvas.py |  346 -------------------------------------
 po/POTFILES.in                    |    2 +-
 4 files changed, 332 insertions(+), 349 deletions(-)
---
diff --git a/pitivi/timeline/Makefile.am b/pitivi/timeline/Makefile.am
index 09b4a3c..fb79ba4 100644
--- a/pitivi/timeline/Makefile.am
+++ b/pitivi/timeline/Makefile.am
@@ -2,7 +2,6 @@ timelinedir = $(libdir)/pitivi/python/pitivi/timeline
 
 timeline_PYTHON =			\
 	__init__.py		\
-	timelinecanvas.py	\
 	timeline.py		\
 	track.py	\
 	curve.py	\
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 2e1bf80..b32178b 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -3,6 +3,7 @@
 #       pitivi/ui/timeline.py
 #
 # Copyright (c) 2005, Edward Hervey <bilboed bilboed com>
+# Copyright (c) 2009, Brandon Lewis <brandon_lewis berkeley edu>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -34,7 +35,6 @@ from gettext import gettext as _
 from pitivi.check import soft_deps
 from pitivi.effects import AUDIO_EFFECT, VIDEO_EFFECT
 
-from timelinecanvas import TimelineCanvas
 from track import TrackControls, TRACK_CONTROL_WIDTH
 
 from pitivi.ui.depsmanager import DepsManager
@@ -46,10 +46,47 @@ from pitivi.utils.timeline import MoveContext, SELECT, Zoomable
 from pitivi.utils.ui import SPACING, TRACK_SPACING, LAYER_HEIGHT_EXPANDED,\
     LAYER_SPACING, TYPE_PITIVI_FILESOURCE, VIDEO_EFFECT_TUPLE, \
     AUDIO_EFFECT_TUPLE, EFFECT_TUPLE, FILESOURCE_TUPLE, TYPE_PITIVI_EFFECT
+import gtk
+import goocanvas
+from gettext import gettext as _
+
+from pitivi.settings import GlobalSettings
+
+from pitivi.timeline.track import Track, TrackObject
+
+from pitivi.ui.prefs import PreferencesDialog
+from pitivi.timeline.curve import KW_LABEL_Y_OVERFLOW
+
+from pitivi.utils.loggable import Loggable
+from pitivi.utils.receiver import receiver, handler
+from pitivi.utils.timeline import Controller, Zoomable
+from pitivi.utils.ui import TRACK_SPACING, unpack_cairo_pattern, \
+        LAYER_HEIGHT_EXPANDED, LAYER_SPACING, SPACING, Point
 
 # FIXME GES Port regression
 # from pitivi.utils.align import AutoAligner
 
+GlobalSettings.addConfigOption('edgeSnapDeadband',
+    section="user-interface",
+    key="edge-snap-deadband",
+    default=5,
+    notify=True)
+
+PreferencesDialog.addNumericPreference('edgeSnapDeadband',
+    section=_("Behavior"),
+    label=_("Snap distance"),
+    description=_("Threshold (in pixels) at which two clips will snap together "
+        "when dragging or trimming."),
+    lower=0)
+
+
+# cursors to be used for resizing objects
+ARROW = gtk.gdk.Cursor(gtk.gdk.ARROW)
+# TODO: replace this with custom cursor
+PLAYHEAD_CURSOR = gtk.gdk.Cursor(gtk.gdk.SB_H_DOUBLE_ARROW)
+
+# Drag and drop constants/tuples
+# FIXME, rethink the way we handle that as it is quite 'hacky'
 DND_EFFECT_LIST = [[VIDEO_EFFECT_TUPLE[0], EFFECT_TUPLE[0]],\
                   [AUDIO_EFFECT_TUPLE[0], EFFECT_TUPLE[0]]]
 VIDEO_EFFECT_LIST = [VIDEO_EFFECT_TUPLE[0], EFFECT_TUPLE[0]],
@@ -121,6 +158,299 @@ ui = '''
 '''
 
 
+class PlayheadController(Controller, Zoomable):
+
+    _cursor = PLAYHEAD_CURSOR
+
+    def __init__(self, *args, **kwargs):
+        Controller.__init__(self, *args, **kwargs)
+
+    def set_pos(self, item, pos):
+        x, y = pos
+        x += self._hadj.get_value()
+        self._canvas.app.current.seeker.seek(Zoomable.pixelToNs(x))
+
+
+class TimelineCanvas(goocanvas.Canvas, Zoomable, Loggable):
+    """
+        The goocanvas widget representing the timeline
+    """
+
+    __gtype_name__ = 'TimelineCanvas'
+    __gsignals__ = {
+        "expose-event": "override",
+    }
+
+    _tracks = None
+
+    def __init__(self, instance, timeline=None):
+        goocanvas.Canvas.__init__(self)
+        Zoomable.__init__(self)
+        Loggable.__init__(self)
+        self.app = instance
+        self._selected_sources = []
+        self._tracks = []
+        self.height = 0
+        self._position = 0
+
+        self._block_size_request = False
+        self.props.integer_layout = True
+        self.props.automatic_bounds = False
+        self.props.clear_background = False
+        self.get_root_item().set_simple_transform(0, 2.0, 1.0, 0)
+
+        self._createUI()
+        self._timeline = timeline
+        self.settings = instance.settings
+
+    def _createUI(self):
+        self._cursor = ARROW
+        root = self.get_root_item()
+        self.tracks = goocanvas.Group()
+        self.tracks.set_simple_transform(0, KW_LABEL_Y_OVERFLOW, 1.0, 0)
+        root.add_child(self.tracks)
+        self._marquee = goocanvas.Rect(
+            parent=root,
+            stroke_pattern=unpack_cairo_pattern(0x33CCFF66),
+            fill_pattern=unpack_cairo_pattern(0x33CCFF66),
+            visibility=goocanvas.ITEM_INVISIBLE)
+        self._playhead = goocanvas.Rect(
+            y=-10,
+            parent=root,
+            line_width=1,
+            fill_color_rgba=0x000000FF,
+            stroke_color_rgba=0xFFFFFFFF,
+            width=3)
+        self._playhead_controller = PlayheadController(self._playhead)
+        self.connect("size-allocate", self._size_allocate_cb)
+        root.connect("motion-notify-event", self._selectionDrag)
+        root.connect("button-press-event", self._selectionStart)
+        root.connect("button-release-event", self._selectionEnd)
+        self.height = (LAYER_HEIGHT_EXPANDED + TRACK_SPACING +
+                LAYER_SPACING) * 2
+        # add some padding for the horizontal scrollbar
+        self.height += 21
+        self.set_size_request(-1, self.height)
+
+    def from_event(self, event):
+        x, y = event.x, event.y
+        x += self.app.gui.timeline.hadj.get_value()
+        return Point(*self.convert_from_pixels(x, y))
+
+    def setExpanded(self, track_object, expanded):
+        track_ui = None
+        for track in self._tracks:
+            if track.track == track_object:
+                track_ui = track
+                break
+
+        track_ui.setExpanded(expanded)
+
+## sets the cursor as appropriate
+
+    def _mouseEnterCb(self, unused_item, unused_target, event):
+        event.window.set_cursor(self._cursor)
+        return True
+
+    def do_expose_event(self, event):
+        allocation = self.get_allocation()
+        width = allocation.width
+        height = allocation.height
+        # draw the canvas background
+        # we must have props.clear_background set to False
+
+        self.style.apply_default_background(event.window,
+            True,
+            gtk.STATE_ACTIVE,
+            event.area,
+            event.area.x, event.area.y,
+            event.area.width, event.area.height)
+
+        goocanvas.Canvas.do_expose_event(self, event)
+
+## implements selection marquee
+
+    _selecting = False
+    _mousedown = None
+    _marquee = None
+    _got_motion_notify = False
+
+    def getItemsInArea(self, x1, y1, x2, y2):
+        '''
+        Permits to get the Non UI L{Track}/L{TrackObject} in a list of set
+        corresponding to the L{Track}/L{TrackObject} which are in the are
+
+        @param x1: The horizontal coordinate of the up left corner of the area
+        @type x1: An C{int}
+        @param y1: The vertical coordinate of the up left corner of the area
+        @type y1: An C{int}
+        @param x2: The horizontal coordinate of the down right corner of the
+                   area
+        @type x2: An C{int}
+        @param x2: The vertical coordinate of the down right corner of the area
+        @type x2: An C{int}
+
+        @returns: A list of L{Track}, L{TrackObject} tuples
+        '''
+        items = self.get_items_in_area(goocanvas.Bounds(x1, y1, x2, y2), True,
+            True, True)
+        if not items:
+            return [], []
+
+        tracks = set()
+        track_objects = set()
+
+        for item in items:
+            if isinstance(item, Track):
+                tracks.add(item.track)
+            elif isinstance(item, TrackObject):
+                track_objects.add(item.element)
+
+        return tracks, track_objects
+
+    def _normalize(self, p1, p2, adjust=0):
+        w, h = p2 - p1
+        x, y = p1
+        if w - adjust < 0:
+            w = abs(w - adjust)
+            x -= w
+        else:
+            w -= adjust
+        if h < 0:
+            h = abs(h)
+            y -= h
+        return (x, y), (w, h)
+
+    def _selectionDrag(self, item, target, event):
+        if self._selecting:
+            self._got_motion_notify = True
+            cur = self.from_event(event)
+            pos, size = self._normalize(self._mousedown, cur,
+                self.app.gui.timeline.hadj.get_value())
+            self._marquee.props.x, self._marquee.props.y = pos
+            self._marquee.props.width, self._marquee.props.height = size
+            return True
+        return False
+
+    def _selectionStart(self, item, target, event):
+        self._selecting = True
+        self._marquee.props.visibility = goocanvas.ITEM_VISIBLE
+        self._mousedown = self.from_event(event)
+        self._marquee.props.width = 0
+        self._marquee.props.height = 0
+        self.pointer_grab(self.get_root_item(), gtk.gdk.POINTER_MOTION_MASK |
+            gtk.gdk.BUTTON_RELEASE_MASK, self._cursor, event.time)
+        return True
+
+    def _selectionEnd(self, item, target, event):
+        seeker = self.app.current.seeker
+        self.pointer_ungrab(self.get_root_item(), event.time)
+        self._selecting = False
+        self._marquee.props.visibility = goocanvas.ITEM_INVISIBLE
+        if not self._got_motion_notify:
+            self._timeline.selection.setSelection([], 0)
+            seeker.seek(Zoomable.pixelToNs(event.x))
+        else:
+            self._got_motion_notify = False
+            mode = 0
+            if event.get_state() & gtk.gdk.SHIFT_MASK:
+                mode = 1
+            if event.get_state() & gtk.gdk.CONTROL_MASK:
+                mode = 2
+            selected = self._objectsUnderMarquee()
+            self.app.projectManager.current.emit("selected-changed", selected)
+            self._timeline.selection.setSelection(self._objectsUnderMarquee(), mode)
+        return True
+
+    def _objectsUnderMarquee(self):
+        items = self.get_items_in_area(self._marquee.get_bounds(), True, True,
+            True)
+        if items:
+            return set((item.element for item in items if isinstance(item,
+                TrackObject) and item.bg in items))
+        return set()
+
+## playhead implementation
+
+    position = 0
+
+    def timelinePositionChanged(self, position):
+        self.position = position
+        self._playhead.props.x = self.nsToPixel(position)
+
+    max_duration = 0
+
+    def setMaxDuration(self, duration):
+        self.max_duration = duration
+        self._request_size()
+
+    def _request_size(self):
+        alloc = self.get_allocation()
+        self.set_bounds(0, 0, alloc.width, alloc.height)
+        self._playhead.props.height = (self.height + SPACING)
+
+    def _size_allocate_cb(self, widget, allocation):
+        self._request_size()
+
+    def zoomChanged(self):
+        self.queue_draw()
+        if self._timeline:
+            self._timeline.dead_band = self.pixelToNs(
+                self.settings.edgeSnapDeadband)
+            #self._timelinePositionChanged(self.position)
+
+## settings callbacks
+
+    def _setSettings(self):
+        self.zoomChanged()
+
+    settings = receiver(_setSettings)
+
+    @handler(settings, "edgeSnapDeadbandChanged")
+    def _edgeSnapDeadbandChangedCb(self, settings):
+        self.zoomChanged()
+
+## Timeline callbacks
+
+    def setTimeline(self, timeline):
+        while self._tracks:
+            self._trackRemoved(None, 0)
+
+        self._timeline = timeline
+        if self._timeline:
+            for track in self._timeline.get_tracks():
+                self._trackAdded(None, track)
+            self._timeline.connect("track-added", self._trackAdded)
+            self._timeline.connect("track-removed", self._trackRemoved)
+        self.zoomChanged()
+
+    def getTimeline(self):
+        return self._timeline
+
+    timeline = property(getTimeline, setTimeline, None, "The timeline property")
+
+    def _trackAdded(self, timeline, track):
+        track = Track(self.app, track, self._timeline)
+        self._tracks.append(track)
+        track.set_canvas(self)
+        self.tracks.add_child(track)
+        self.regroupTracks()
+
+    def _trackRemoved(self, unused_timeline, position):
+        track = self._tracks[position]
+        del self._tracks[position]
+        track.remove()
+        self.regroupTracks()
+
+    def regroupTracks(self):
+        height = 0
+        for i, track in enumerate(self._tracks):
+            track.set_simple_transform(0, height, 1, 0)
+            height += track.height + TRACK_SPACING
+        self.height = height
+        self._request_size()
+
+
 class TimelineControls(gtk.VBox, Loggable):
     """Contains the timeline track names."""
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e1ca1b4..ae0bb39 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -21,8 +21,8 @@ pitivi/project.py
 pitivi/settings.py
 pitivi/medialibrary.py
 
-pitivi/timeline/timelinecanvas.py
 pitivi/timeline/timeline.py
+pitivi/timeline/track.py
 
 pitivi/ui/basetabs.py
 pitivi/ui/clipproperties.py



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