[pitivi] add timeline controls next to timeline canvas
- From: Edward Hervey <edwardrv src gnome org>
- To: svn-commits-list gnome org
- Subject: [pitivi] add timeline controls next to timeline canvas
- Date: Wed, 18 Mar 2009 14:08:18 -0400 (EDT)
commit d2aca9ad64f2a1774c908e6f7944342da9918f56
Author: Brandon Lewis <brandon_lewis berkeley edu>
Date: Sat Feb 28 12:59:54 2009 -0800
add timeline controls next to timeline canvas
set priority based on y-axis
add max-priority property to timeline.track
fix function signature
disable vertical movement for now, we have a long way to go
start working on track controls
fix some issues
---
pitivi/timeline/track.py | 20 +++++++++
pitivi/ui/timeline.py | 44 +++++++++++++++-----
pitivi/ui/timelinecanvas.py | 9 ++--
pitivi/ui/timelinecontrols.py | 46 ++++++++++++++++++++
pitivi/ui/track.py | 19 +++++++--
pitivi/ui/trackobject.py | 92 +++++++++++++++++++++++++++-------------
6 files changed, 181 insertions(+), 49 deletions(-)
diff --git a/pitivi/timeline/track.py b/pitivi/timeline/track.py
index a9fe944..c858b1f 100644
--- a/pitivi/timeline/track.py
+++ b/pitivi/timeline/track.py
@@ -365,6 +365,24 @@ class Track(object, Signallable):
max_priority = property(_getMaxPriority)
+ __max_priority = 0
+
+ @property
+ def max_priority(self):
+ return self.__max_priority
+
+ def _trackObjectPriorityCb(self, trackobject, priority):
+ op = self.__max_priority
+ self.__max_priority = max(self.__max_priority, priority)
+ if op != self.__max_priority:
+ self.emit("max-priority-changed")
+
+ def _connectToTrackObjectSignals(self, track_object):
+ track_object.connect("priority-changed", self._trackObjectPriorityCb)
+
+ def _disconnectTrackObjectSignals(self, track_object):
+ track_object.disconnect_by_function(self._trackObjectPriorityCb)
+
def addTrackObject(self, track_object):
if track_object.track is not None:
raise TrackError()
@@ -378,6 +396,7 @@ class Track(object, Signallable):
self.track_objects.append(track_object)
track_object.makeBin()
+ self._connectToTrackObjectSignals(track_object)
self._updateMaxPriority()
self._connectToTrackObject(track_object)
@@ -399,6 +418,7 @@ class Track(object, Signallable):
self.track_objects.remove(track_object)
track_object.track = None
+ self._disconnectTrackObjectSignals(track_object)
self._updateMaxPriority()
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index 8cd244d..3e012d1 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -33,6 +33,7 @@ import gobject
from gettext import gettext as _
from timelinecanvas import TimelineCanvas
+from timelinecontrols import TimelineControls
from pitivi.receiver import receiver, handler
from zoominterface import Zoomable
@@ -85,9 +86,8 @@ ui = '''
# | +--Track(SmartGroup)
# |
# +--Status Bar ??
-#
-class Timeline(gtk.VBox, Loggable, Zoomable):
+class Timeline(gtk.Table, Loggable, Zoomable):
# the screen width of the current unit
unit_width = 10
@@ -96,7 +96,7 @@ class Timeline(gtk.VBox, Loggable, Zoomable):
def __init__(self, ui_manager):
- gtk.VBox.__init__(self)
+ gtk.Table.__init__(self, rows=2, columns=1, homogeneous=False)
Loggable.__init__(self)
Zoomable.__init__(self)
self.log("Creating Timeline")
@@ -114,19 +114,28 @@ class Timeline(gtk.VBox, Loggable, Zoomable):
def _createUI(self):
self.leftSizeGroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
self.hadj = gtk.Adjustment()
+ self.vadj = gtk.Adjustment()
+
+ # controls for tracks and layers
+ self._controls = TimelineControls(self.timeline)
+ controlwindow = gtk.ScrolledWindow(None, self.vadj)
+ controlwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
+ controlwindow.add_with_viewport(self._controls)
+ self.attach(controlwindow, 0, 1, 1, 2, xoptions=0)
+
+ # timeline ruler
self.ruler = ruler.ScaleRuler(self.hadj)
self.ruler.set_size_request(0, 35)
self.ruler.set_border_width(2)
- self.pack_start(self.ruler, expand=False, fill=True)
+ self.attach(self.ruler, 1, 2, 0, 1, yoptions=0)
- # List of TimelineCanvas
+ # proportional timeline
self._canvas = TimelineCanvas(self.timeline)
-
- self.scrolledWindow = gtk.ScrolledWindow(self.hadj)
- self.scrolledWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.scrolledWindow.add(self._canvas)
+ timelinewindow = gtk.ScrolledWindow(self.hadj)
+ timelinewindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ timelinewindow.add(self._canvas)
#FIXME: remove padding between scrollbar and scrolled window
- self.pack_start(self.scrolledWindow, expand=True)
+ self.attach(timelinewindow, 1, 2, 1, 2)
# drag and drop
self.drag_dest_set(gtk.DEST_DEFAULT_MOTION,
@@ -164,6 +173,17 @@ class Timeline(gtk.VBox, Loggable, Zoomable):
self.ui_manager.insert_action_group(self.actiongroup, 0)
self.ui_manager.add_ui_from_string(ui)
+ # drag and drop
+ self.drag_dest_set(gtk.DEST_DEFAULT_MOTION,
+ [dnd.FILESOURCE_TUPLE],
+ gtk.gdk.ACTION_COPY)
+
+ self.connect("drag-data-received", self._dragDataReceivedCb)
+ self.connect("drag-leave", self._dragLeaveCb)
+ self.connect("drag-drop", self._dragDropCb)
+ self.connect("drag-motion", self._dragMotionCb)
+
+
## Drag and Drop callbacks
def _dragMotionCb(self, unused, context, x, y, timestamp):
@@ -218,7 +238,9 @@ class Timeline(gtk.VBox, Loggable, Zoomable):
for factory in self._factories]
def _move_temp_source(self, x, y):
- x, y = self._canvas.convert_from_pixels(x - 10, y)
+ x1, y1, x2, y2 = self._controls.get_allocation()
+ offset = 10 + (x2 - x1)
+ x, y = self._canvas.convert_from_pixels(x - offset, y)
delta = Zoomable.pixelToNs(x)
for obj in self._temp_objects:
obj.setStart(max(0, delta), snap=True)
diff --git a/pitivi/ui/timelinecanvas.py b/pitivi/ui/timelinecanvas.py
index b42894d..e2ce9ec 100644
--- a/pitivi/ui/timelinecanvas.py
+++ b/pitivi/ui/timelinecanvas.py
@@ -27,6 +27,8 @@ from pitivi.ui.track import Track
from pitivi.ui.trackobject import TrackObject
from pitivi.ui.point import Point
from pitivi.ui.zoominterface import Zoomable
+from common import TRACK_SPACING
+import gtk
# cursors to be used for resizing objects
ARROW = gtk.gdk.Cursor(gtk.gdk.ARROW)
@@ -227,9 +229,8 @@ class TimelineCanvas(goocanvas.Canvas, Zoomable):
self._regroup_tracks()
def _regroup_tracks(self):
+ height = 0
for i, track in enumerate(self._tracks):
- # FIXME: hard-coding track height, because this won't be updated
- # later
- height = 50
- track.set_simple_transform(0, i * (height + 10), 1, 0)
+ track.set_simple_transform(0, height, 1, 0)
+ height += track.height + TRACK_SPACING
self._request_size()
diff --git a/pitivi/ui/timelinecontrols.py b/pitivi/ui/timelinecontrols.py
new file mode 100644
index 0000000..81f0522
--- /dev/null
+++ b/pitivi/ui/timelinecontrols.py
@@ -0,0 +1,46 @@
+import gtk
+from pitivi.receiver import receiver, handler
+import pitivi.stream as stream
+from gettext import gettext as _
+from common import LAYER_HEIGHT_EXPANDED, LAYER_SPACING
+
+TRACK_CONTROL_WIDTH = 75
+
+def track_name(track):
+ stream_type = type(track.stream)
+ if stream_type == stream.AudioStream:
+ return _("<b>Audio:</b>")
+ elif stream_type == stream.VideoStream:
+ return _("<b>Video:</b>")
+ elif stream_type == stream.TextStream:
+ return _("<b>Text:</b>")
+
+class TrackControls(gtk.Expander):
+
+ def __init__(self, track):
+ gtk.Expander.__init__(self, track_name(track))
+ self.track = track
+ self.set_size_request(TRACK_CONTROL_WIDTH, LAYER_HEIGHT_EXPANDED)
+ self.tracks = {}
+
+class TimelineControls(gtk.HBox):
+
+ def __init__(self, timeline):
+ gtk.HBox.__init__(self)
+ self.timeline = timeline
+ self.set_size_request(TRACK_CONTROL_WIDTH, 50)
+ self.set_spacing(LAYER_SPACING)
+
+ timeline = receiver()
+
+ @handler(timeline, "track-added")
+ def _trackAdded(self, timeline, track):
+ tc = TrackControls(track)
+ self.pack_start(tc)
+ tc.show()
+ self.tracks[track] = tc
+
+ @handler(timeline, "track-removed")
+ def _trackRemoved(self, timeline, track):
+ self.remove(self.tracks[track])
+
diff --git a/pitivi/ui/track.py b/pitivi/ui/track.py
index 0833e41..75ed2d6 100644
--- a/pitivi/ui/track.py
+++ b/pitivi/ui/track.py
@@ -1,21 +1,32 @@
from pitivi.ui.zoominterface import Zoomable
from pitivi.ui.trackobject import TrackObject
from pitivi.receiver import receiver, handler
+from common import LAYER_HEIGHT_EXPANDED, LAYER_SPACING
import goocanvas
-# TODO: layer managment controls
-
class Track(goocanvas.Group, Zoomable):
__gtype_name__ = 'Track'
- track = receiver()
-
def __init__(self, track, timeline=None):
goocanvas.Group.__init__(self)
Zoomable.__init__(self)
self.widgets = {}
self.track = track
self.timeline = timeline
+ self.max_priority = 0
+
+## Properties
+
+ def getHeight(self):
+ return (1 + self.max_priority) * (LAYER_HEIGHT_EXPANDED + LAYER_SPACING)
+
+ height = property(getHeight)
+
+## Public API
+
+## track signals
+
+ track = receiver()
@handler(track, "track-object-added")
def _objectAdded(self, unused_timeline, track_object):
diff --git a/pitivi/ui/trackobject.py b/pitivi/ui/trackobject.py
index 43c2315..15a0a3e 100644
--- a/pitivi/ui/trackobject.py
+++ b/pitivi/ui/trackobject.py
@@ -12,6 +12,9 @@ import controller
from zoominterface import Zoomable
from pitivi.timeline.track import TrackError
from preview import Preview
+import gst
+from common import LAYER_HEIGHT_EXPANDED, LAYER_HEIGHT_COLLAPSED
+from common import LAYER_SPACING
LEFT_SIDE = gtk.gdk.Cursor(gtk.gdk.LEFT_SIDE)
RIGHT_SIDE = gtk.gdk.Cursor(gtk.gdk.RIGHT_SIDE)
@@ -44,10 +47,6 @@ class TimelineController(controller.Controller):
def drag_end(self):
self._view.timeline.rebuildEdges()
- def set_pos(self, item, pos):
- self._view.element.setStart(max(self._view.pixelToNs(pos[0]), 0),
- snap=True)
-
class TrimHandle(View, goocanvas.Image, Zoomable):
"""A component of a TrackObject which manage's the source's edit
@@ -100,9 +99,6 @@ class EndHandle(TrimHandle):
class TrackObject(View, goocanvas.Group, Zoomable):
- element = receiver()
-
- __HEIGHT__ = 50
__BACKGROUND__ = 0x3182bdC0
__BORDER__ = 0xffea00FF
@@ -121,6 +117,13 @@ class TrackObject(View, goocanvas.Group, Zoomable):
self._view.timeline.setSelectionToObj(
self._view.element, mode)
+ def set_pos(self, item, pos):
+ x, y = pos
+ self._view.element.setStart(max(self._view.pixelToNs(x), 0),
+ snap=True)
+ #priority = int(max(0, y // (LAYER_HEIGHT_EXPANDED + LAYER_SPACING)))
+ #self._view.element.priority = priority
+
def __init__(self, element, track, timeline):
goocanvas.Group.__init__(self)
View.__init__(self)
@@ -131,7 +134,7 @@ class TrackObject(View, goocanvas.Group, Zoomable):
self.timeline = timeline
self.bg = goocanvas.Rect(
- height=self.__HEIGHT__,
+ height=self.height,
fill_color_rgba=self.__BACKGROUND__,
stroke_color_rgba=self.__BORDER__,
line_width=0)
@@ -159,9 +162,9 @@ class TrackObject(View, goocanvas.Group, Zoomable):
self.namewidth = twidth
self.start_handle = StartHandle(element, timeline,
- height=self.__HEIGHT__)
+ height=self.height)
self.end_handle = EndHandle(element, timeline,
- height=self.__HEIGHT__)
+ height=self.height)
for thing in (self.bg, self.content, self.start_handle,
self.end_handle, self.namebg, self.name):
@@ -171,6 +174,23 @@ class TrackObject(View, goocanvas.Group, Zoomable):
self.zoomChanged()
self.normal()
+## Properties
+
+ __height = LAYER_HEIGHT_EXPANDED
+
+ def setHeight(self, height):
+ self.__height
+ self.start_handle.props.height = height
+ self.end_handle.props.height = height
+ self.__update()
+
+ def getHeight(self):
+ return self.__height
+
+ height = property(getHeight, setHeight)
+
+## Public API
+
def focus(self):
self.start_handle.focus()
self.end_handle.focus()
@@ -180,37 +200,49 @@ class TrackObject(View, goocanvas.Group, Zoomable):
self.end_handle.unfocus()
def zoomChanged(self):
- self._startDurationChangedCb(self.element, self.element.start,
- self.element.duration)
+ self.__update()
- @handler(element, "start-changed")
- def _startChangedCb(self, track_object, start):
- self._startDurationChangedCb(track_object,
- track_object.start, track_object.duration)
+ def expand(self):
+ self.content.props.visibility = goocanvas.ITEM_VISIBLE
+ self.height = LAYER_HEIGHT
+
+ def collapse(self):
+ self.content.props.visibility = goocanvas.ITEM_INVISIBLE
+
+## element signals
+
+ element = receiver()
+ @handler(element, "start-changed")
@handler(element, "duration-changed")
- def _startChangedCb(self, track_object, start):
- self._startDurationChangedCb(track_object,
- track_object.start, track_object.duration)
+ def startChangedCb(self, track_object, start):
+ self.__update()
+
+ @handler(element, "selected-changed")
+ def selected_changed(self, element, state):
+ if element.selected:
+ self.bg.props.line_width = 2.0
+ else:
+ self.bg.props.line_width = 0
- def _startDurationChangedCb(self, obj, start, duration):
- self.set_simple_transform(self.nsToPixel(start), 0, 1, 0)
- width = self.nsToPixel(duration)
+ @handler(element, "priority-changed")
+ def priority_changed(self, element, priority):
+ self.__update()
+
+ def __update(self):
+ x = self.nsToPixel(self.element.start)
+ y = (LAYER_HEIGHT_EXPANDED + LAYER_SPACING) * self.element.priority
+ self.set_simple_transform(x, y, 1, 0)
+
+ width = self.nsToPixel(self.element.duration)
w = width - self.end_handle.props.width
self.name.props.clip_path = "M%g,%g h%g v%g h-%g z" % (
- 0, 0, w, self.__HEIGHT__, w)
+ 0, 0, w, self.height, w)
if w - 10 > 0:
self.namebg.props.width = min(w - 8, self.namewidth)
self.namebg.props.visibility = goocanvas.ITEM_VISIBLE
else:
self.namebg.props.visibility = goocanvas.ITEM_INVISIBLE
self.bg.props.width = width
- # place end handle at appropriate distance
self.end_handle.props.x = w
- @handler(element, "selected-changed")
- def _selected_changed(self, element, state):
- if element.selected:
- self.bg.props.line_width = 2.0
- else:
- self.bg.props.line_width = 0
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]