[pitivi/ges: 64/287] Start reimplementing Drag and drop better
- From: Jean-FranÃois Fortin Tam <jfft src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi/ges: 64/287] Start reimplementing Drag and drop better
- Date: Thu, 15 Mar 2012 16:31:12 +0000 (UTC)
commit 8fcb081f4bb678db2ae179218d945740579f02dc
Author: Thibault Saunier <thibault saunier collabora com>
Date: Mon Oct 24 16:29:00 2011 +0200
Start reimplementing Drag and drop better
We should reintroduce the notion of selection so we can drag
and drop various clips from the sourcelist
pitivi/timeline/timeline.py | 218 +++++++++++++++++++++++--------------------
pitivi/ui/timeline.py | 69 +++++++-------
2 files changed, 155 insertions(+), 132 deletions(-)
---
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index c3a1c9d..e6ec807 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -23,6 +23,7 @@
import ges
from pitivi.utils import infinity
+from pitivi.timeline.gap import Gap, SmallestGapsFinder, invalid_gap
#from pitivi.timeline.align import AutoAligner
@@ -52,13 +53,13 @@ class EditingContext(object):
def __init__(self, timeline, focus, other):
"""
@param timeline: the timeline to edit
- @type timeline: instance of L{pitivi.timeline.timeline.Timeline}
+ @type timeline: instance of L{ges.Timeline}
- @param focus: the TimelineObject or TrackObject which is to be the the
+ @param focus: the TimelineObject or TrackObject which is to be the
main target of interactive editing, such as the object directly under the
mouse pointer
- @type focus: L{pitivi.timeline.timeline.TimelineObject} or
- L{pitivi.timeline.trackTrackObject}
+ @type focus: L{ges.TimelineObject} or
+ L{ges.TrackObject}
@param other: a set of objects which are the secondary targets of
interactive editing, such as objects in the current selection.
@@ -73,39 +74,38 @@ class EditingContext(object):
self.other = other
self.focus = focus
self.timeline = timeline
- self._snap = False
+ self._snap = True
self._mode = self.DEFAULT
- self._last_position = focus.get_property("start")
- self._last_priority = focus.get_property("priority")
+ self._last_position = focus.props.start
+ self._last_priority = focus.props.priority
- #self.timeline.disableUpdates()
+ self.timeline.enable_update(False)
def _getOffsets(self, start_offset, priority_offset, timeline_objects):
offsets = {}
- for timeline_object in timeline_objects:
- offsets[timeline_object] = (timeline_object.get_property("start") - start_offset,
- timeline_object.get_property("priority") - priority_offset)
+ for tlobj in timeline_objects:
+ offsets[tlobj] = (tlobj.props.start - start_offset,
+ tlobj.props.priority - priority_offset)
return offsets
- def _getTimelineObjectValues(self, timeline_object):
- return (timeline_object.get_property("start"), timeline_object.get_property("duration"),
- timeline_object.get_property("in_point"),
- timeline_object.get_property("priority"))
+ def _getTimelineObjectValues(self, tlobj):
+ return (tlobj.props.start, tlobj.props.duration,
+ tlobj.props.in_point,
+ tlobj.props.priority)
def _saveValues(self, timeline_objects):
- return dict(((timeline_object,
- self._getTimelineObjectValues(timeline_object))
- for timeline_object in timeline_objects))
+ return dict(((tlobj,
+ self._getTimelineObjectValues(tlobj))
+ for tlobj in timeline_objects))
def _restoreValues(self, values):
- for timeline_object, (start, duration, in_point, media_dur, pri) in \
+ for tlobj, (start, duration, in_point, pri) in \
values.iteritems():
- timeline_object.start = start
- timeline_object.duration = duration
- timeline_object.in_point = in_point
- timeline_object.media_duration = media_dur
- timeline_object.priority = pri
+ tlobj.props.start = start
+ tlobj.props.duration = duration
+ tlobj.props.in_point = in_point
+ tlobj.props.priority = pri
def _getSpan(self, earliest, objs):
return max((obj.start + obj.duration for obj in objs)) - earliest
@@ -113,8 +113,7 @@ class EditingContext(object):
def finish(self):
"""Clean up timeline for normal editing"""
# TODO: post undo / redo action here
- return
- self.timeline.enableUpdates()
+ self.timeline.enable_update(True)
def setMode(self, mode):
"""Set the current editing mode.
@@ -179,13 +178,11 @@ class EditingContext(object):
return position, priority
- def _getGapsAtPriority(self, priority, timeline_objects, tracks=None):
+ def _getGapsForLayer(self, timeline_objects, tracks=None):
gaps = SmallestGapsFinder(timeline_objects)
- prio_diff = priority - self.focus.priority
- for timeline_object in timeline_objects:
- left_gap, right_gap = Gap.findAroundObject(timeline_object,
- timeline_object.priority + prio_diff, tracks)
+ for tlobj in timeline_objects:
+ left_gap, right_gap = Gap.findAroundObject(tlobj)
gaps.update(left_gap, right_gap)
return gaps.left_gap, gaps.right_gap
@@ -207,60 +204,66 @@ class MoveContext(EditingContext):
self.tracks = set([])
all_objects = set(other)
all_objects.add(focus)
- self.layersList = []
+ self.layer_lst = []
for obj in all_objects:
if isinstance(obj, ges.TrackObject):
- timeline_object = obj.get_timeline_object()
+ tlobj = obj.get_timeline_object()
self.tracks.add(obj.get_track())
else:
- timeline_object = obj
- timeline_object_tracks = set(track_object.get_track() for track_object
- in timeline_object.get_track_objects())
+ tlobj = obj
+ timeline_object_tracks = \
+ set(track_object.get_track() for track_object
+ in tlobj.get_track_objects())
self.tracks.update(timeline_object_tracks)
- self.timeline_objects.add(timeline_object)
+ self.timeline_objects.add(tlobj)
- self.default_originals[timeline_object] = \
- self._getTimelineObjectValues(timeline_object)
+ self.default_originals[tlobj] = \
+ self._getTimelineObjectValues(tlobj)
- earliest = min(earliest, timeline_object.get_property("start"))
- latest = max(latest,
- timeline_object.get_property("start") + timeline_object.get_property("duration"))
- min_priority = min(min_priority, timeline_object.get_property("priority"))
+ earliest = min(earliest, tlobj.props.start)
+ latest = max(latest, tlobj.props.start + tlobj.props.duration)
+ min_priority = min(min_priority, tlobj.props.priority)
- self.offsets = self._getOffsets(self.focus.get_property("start"), self.focus.get_property("priority"),
- self.timeline_objects)
+ self.offsets = self._getOffsets(self.focus.props.start,
+ self.focus.props.priority, self.timeline_objects)
- self.min_priority = focus.get_property("priority") - min_priority
- self.min_position = focus.get_property("start") - earliest
+ self.min_priority = focus.props.priority - min_priority
+ self.min_position = focus.props.start - earliest
# get the span over all clips for edge snapping
self.default_span = latest - earliest
- #ripple = timeline.getObjsAfterTime(latest)
- #self.ripple_offsets = self._getOffsets(self.focus.get_property("start"),
- #self.focus.get_property("priority"), ripple)
+ if isinstance(focus, ges.TrackObject):
+ layer = focus.get_timeline_object().get_layer()
+ else:
+ layer = focus.get_layer()
+
+ ripple = [obj for obj in layer.get_objects() \
+ if obj.props.start > latest]
+ self.ripple_offsets = self._getOffsets(self.focus.props.start,
+ self.focus.props.priority, ripple)
# get the span over all clips for ripple editing
- #for timeline_object in ripple:
- #latest = max(latest, timeline_object.get_property("start") +
- #timeline_object.get_property("duration"))
- #self.ripple_span = latest - earliest
+ for tlobj in ripple:
+ latest = max(latest, tlobj.props.start +
+ tlobj.props.duration)
+ self.ripple_span = latest - earliest
# save default values
- #self.ripple_originals = self._saveValues(ripple)
+ self.ripple_originals = self._saveValues(ripple)
- #self.timeline_objects_plus_ripple = set(self.timeline_objects)
- #self.timeline_objects_plus_ripple.update(ripple)
+ self.timeline_objects_plus_ripple = set(self.timeline_objects)
+ self.timeline_objects_plus_ripple.update(ripple)
- def _getGapsAtPriority(self, priority):
+ def _getGapsForLayer(self):
if self._mode == self.RIPPLE:
timeline_objects = self.timeline_objects_plus_ripple
else:
timeline_objects = self.timeline_objects
- return EditingContext._getGapsAtPriority(self,
- priority, timeline_objects, self.tracks)
+ return EditingContext._getGapsForLayer(self,
+ timeline_objects, self.tracks)
def setMode(self, mode):
if mode == self.ROLL:
@@ -276,11 +279,12 @@ class MoveContext(EditingContext):
focus_timeline_object = self.focus.get_timeline_object()
else:
focus_timeline_object = self.focus
+
initial_position = self.default_originals[focus_timeline_object][0]
initial_priority = self.default_originals[focus_timeline_object][-1]
- final_priority = self.focus.get_property("priority")
- final_position = self.focus.get_property("start")
+ final_priority = self.focus.props.priority
+ final_position = self.focus.props.start
priority = final_priority
@@ -290,10 +294,10 @@ class MoveContext(EditingContext):
EditingContext.finish(self)
return
- # adjust priority
+ # adjust layer
overlap = False
while True:
- left_gap, right_gap = self._getGapsAtPriority(priority)
+ left_gap, right_gap = self._getGapsForLayer()
if left_gap is invalid_gap or right_gap is invalid_gap:
overlap = True
@@ -317,7 +321,7 @@ class MoveContext(EditingContext):
self._defaultTo(initial_position, priority)
delta = final_position - initial_position
- left_gap, right_gap = self._getGapsAtPriority(priority)
+ left_gap, right_gap = self._getGapsForLayer(priority)
if delta > 0 and right_gap.duration < delta:
final_position = initial_position + right_gap.duration
@@ -336,43 +340,51 @@ class MoveContext(EditingContext):
@param end: The stop position to snap.
@returns: The snapped value if within the dead_band.
"""
- edge, diff = self.edges.snapToEdge(start, end)
+ #FIXME GES port, handle properly the snap to edge function
+ #edge, diff = self.edges.snapToEdge(start, end)
- if self.dead_band != -1 and diff <= self.dead_band:
- return edge
+ #if self.dead_band != -1 and diff <= self.dead_band:
+ #return edge
return start
def _defaultTo(self, position, priority):
if self._snap:
- position = self.timeline.snapToEdge(position,
+ position = self.snapToEdge(position,
position + self.default_span)
priority = max(self.min_priority, priority)
obj = self.focus
+
+ # We make sure to work with sources for the drag
+ # and drop
if isinstance(self.focus, ges.TrackFileSource):
obj = self.focus.get_timeline_object()
- if obj.get_layer().get_property("priority") != priority:
+ elif isinstance(self.focus, ges.TrackOperation):
+ return
+
+ if obj.get_layer().props.priority != priority:
origin_layer = obj.get_layer()
moved = False
for layer in self.timeline.get_layers():
- if layer.get_property("priority") == priority:
+ if layer.props.priority == priority:
obj.move_to_layer(layer)
moved = True
if not moved:
layer = ges.TimelineLayer()
- layer.set_property("auto-transition", True)
+ layer.props.auto_transition = True
self.timeline.add_layer(layer)
- layer.set_property("priority", priority)
+ layer.props.priority = priority
obj.move_to_layer(layer)
- self.layersList.append(layer)
+ self.layer_lst.append(layer)
+
if position < 0:
position = 0
- self.focus.set_property("start", long(position))
+
+ self.focus.props.start = long(position)
for obj, (s_offset, p_offset) in self.offsets.iteritems():
- obj.set_property("start", long(position + s_offset))
- #obj.get_layer().set_property ("priority", priority + p_offset)
+ obj.props.start = long(position + s_offset)
return position, priority
@@ -381,11 +393,11 @@ class MoveContext(EditingContext):
def _rippleTo(self, position, priority):
if self._snap:
- position = self.timeline.snapToEdge(position,
+ position = self.snapToEdge(position,
position + self.ripple_span)
priority = max(self.min_priority, priority)
- left_gap, right_gap = self._getGapsAtPriority(priority)
+ left_gap, right_gap = self._getGapsForLayer(priority)
if left_gap is invalid_gap or right_gap is invalid_gap:
if priority == self._last_priority:
@@ -421,7 +433,7 @@ class TrimStartContext(EditingContext):
#self.adjacent_originals = self._saveValues(self.adjacent)
self.tracks = set([])
#if isinstance(self.focus, TrackObject):
- #focus_timeline_object = self.focus.timeline_object
+ #focus_timeline_object = self.focus.tlobj
#self.tracks.add(self.focus.track)
#else:
if isinstance(self.focus, ges.TrackFileSource):
@@ -435,7 +447,7 @@ class TrimStartContext(EditingContext):
self.focus_timeline_object = focus_timeline_object
self.default_originals = self._saveValues([focus_timeline_object])
#ripple = self.timeline.getObjsBeforeTime(focus.start)
- #assert not focus.timeline_object in ripple or focus.duration == 0
+ #assert not focus.tlobj in ripple or focus.duration == 0
#self.ripple_originals = self._saveValues(ripple)
#self.ripple_offsets = self._getOffsets(focus.start, focus.priority,
#ripple)
@@ -460,7 +472,7 @@ class TrimStartContext(EditingContext):
latest = earliest + self.focus.factory.duration
if self.snap:
- position = self.timeline.snapToEdge(position)
+ position = self.snapToEdge(position)
position = min(latest, max(position, earliest))
self.focus.trimStart(position)
@@ -474,20 +486,21 @@ class TrimStartContext(EditingContext):
self._restoreValues(self.ripple_originals)
def _defaultTo(self, position, priority):
- start = self.focus.get_property("start")
+ start = self.focus.props.start
earliest = max(0, position - self.focus.starting_start)
- self.focus.set_property("in-point", earliest)
- self.focus.set_property("start", position)
- self.focus.set_property("duration", self.focus.get_property("max-duration") - self.focus.get_property("in-point"))
+ self.focus.props.in_point = earliest
+ self.focus.props.start = position
+ self.focus.props.duration = self.focus.props.max_duration - \
+ self.focus.props.in_point
return position, priority
def finish(self):
initial_position = self.default_originals[self.focus_timeline_object][0]
- self.focus.starting_start = self.focus.get_property("start")
+ self.focus.starting_start = self.focus.props.start
timeline_objects = [self.focus_timeline_object]
EditingContext.finish(self)
- return
- left_gap, right_gap = self._getGapsAtPriority(self.focus.priority,
+
+ left_gap, right_gap = self._getGapsForLayer(self.focus.priority,
timeline_objects, self.tracks)
if left_gap is invalid_gap:
@@ -514,16 +527,21 @@ class TrimEndContext(EditingContext):
self.focus_timeline_object = focus_timeline_object
self.default_originals = self._saveValues([focus_timeline_object])
- reference = focus.get_property("start") + focus.get_property("duration")
- #ripple = self.timeline.getObjsAfterTime(reference)
+ if isinstance(focus, ges.TrackObject):
+ layer = focus.get_timeline_object().get_layer()
+ else:
+ layer = focus.get_layer()
+ reference = focus.props.start + focus.props.duration
+ ripple = [obj for obj in layer.get_objects() \
+ if obj.props.start > reference]
- #self.ripple_originals = self._saveValues(ripple)
- #self.ripple_offsets = self._getOffsets(reference, self.focus.get_priority(),
- #ripple)
+ self.ripple_originals = self._saveValues(ripple)
+ self.ripple_offsets = self._getOffsets(reference, self.focus.get_priority(),
+ ripple)
def _rollTo(self, position, priority):
if self._snap:
- position = self.timeline.snapToEdge(position)
+ position = self.snapToEdge(position)
duration = max(0, position - self.focus.start)
self.focus.setDuration(duration)
for obj in self.adjacent:
@@ -537,7 +555,7 @@ class TrimEndContext(EditingContext):
earliest = self.focus.start - self.focus.in_point
latest = earliest + self.focus.factory.duration
if self.snap:
- position = self.timeline.snapToEdge(position)
+ position = self.snapToEdge(position)
position = min(latest, max(position, earliest))
duration = position - self.focus.start
self.focus.setDuration(duration)
@@ -550,9 +568,9 @@ class TrimEndContext(EditingContext):
self._restoreValues(self.ripple_originals)
def _defaultTo(self, position, priority):
- duration = max(0, position - self.focus.get_property("start"))
+ duration = max(0, position - self.focus.props.start)
duration = min(duration, self.focus.max_duration)
- self.focus.set_property("duration", duration)
+ self.focus.props.duration = duration
return position, priority
@@ -564,8 +582,8 @@ class TrimEndContext(EditingContext):
absolute_initial_duration = initial_position + initial_duration
timeline_objects = [self.focus_timeline_object]
- return
- left_gap, right_gap = self._getGapsAtPriority(self.focus.priority,
+
+ left_gap, right_gap = self._getGapsForLayer(self.focus.priority,
timeline_objects, self.tracks)
if right_gap is invalid_gap:
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index 20c8c7c..a5c7e87 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -194,7 +194,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self._updateZoom = True
self.ui_manager = ui_manager
self.app = instance
- self._temp_objects = None
+ self._temp_objects = []
self._factories = None
self._finish_drag = False
self._position = 0
@@ -208,8 +208,6 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self._tcks_sig_ids = {}
- self._temp_objects = []
-
def _createUI(self):
self.leftSizeGroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
self.props.row_spacing = 2
@@ -402,33 +400,42 @@ class Timeline(gtk.Table, Loggable, Zoomable):
def _dragMotionCb(self, unused, context, x, y, timestamp):
- atom = gtk.gdk.atom_intern(dnd.FILESOURCE_TUPLE[0])
+ if self._factories is None:
+ if context.targets in DND_EFFECT_LIST:
+ atom = gtk.gdk.atom_intern(dnd.EFFECT_TUPLE[0])
+ else:
+ atom = gtk.gdk.atom_intern(dnd.FILESOURCE_TUPLE[0])
- self.drag_get_data(context, atom, timestamp)
- self.drag_highlight()
- if context.targets not in DND_EFFECT_LIST:
- if not self._temp_objects:
- self._add_temp_source()
- focus = self._temp_objects[0]
- self._move_context = MoveContext(self.timeline,
- focus, set(self._temp_objects[1:]))
- self._move_temp_source(self.hadj.props.value + x, y)
+ self.drag_get_data(context, atom, timestamp)
+ self.drag_highlight()
+ else:
+ if context.targets not in DND_EFFECT_LIST:
+ if not self._temp_objects:
+ self.timeline.enable_update(False)
+ self._add_temp_source()
+ focus = self._temp_objects[0]
+ self._move_context = MoveContext(self.timeline,
+ focus, set(self._temp_objects[1:]))
+ self._move_temp_source(self.hadj.props.value + x, y)
return True
def _dragLeaveCb(self, unused_layout, context, unused_tstamp):
- if self._temp_objects:
- self._temp_objects = []
-
+ self._temp_objects = []
self.drag_unhighlight()
- self.app.projectManager.current.timeline.enable_update(True)
+ self.timeline.enable_update(True)
def _dragDropCb(self, widget, context, x, y, timestamp):
- #FIXME GES break, reimplement me
if context.targets not in DND_EFFECT_LIST:
self.app.action_log.begin("add clip")
+ self.selected = self._temp_objects
+ self._project.emit("selected-changed", set(self.selected))
+
+ self._move_context.finish()
self.app.action_log.commit()
+ context.drop_finish(True, timestamp)
return True
+
elif context.targets in DND_EFFECT_LIST:
if not self.timeline.timeline_objects:
return False
@@ -437,7 +444,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
if timeline_objs:
self.app.action_log.begin("add effect")
self.timeline.addEffectFactoryOnObject(factory,
- timeline_objects=timeline_objs)
+ timeline_objects=timeline_objs)
self.app.action_log.commit()
self._factories = None
self.app.current.seeker.seek(self._position)
@@ -471,16 +478,10 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.app.projectManager.current.timeline.enable_update(False)
self.log("SimpleTimeline, targetType:%d, selection.data:%s" %
(targetType, selection.data))
- # FIXME: let's have just one target type, call it
- # TYPE_PITIVI_OBJECTFACTORY.
- # TODO: handle uri targets by doign an import-add. This would look
- # something like this:
- # tell current project to import the uri
- # wait for source-added signal, meanwhile ignore dragMotion signals
- # when ready, add factories to the timeline.
self.selection_data = selection.data
- if targetType not in [dnd.TYPE_PITIVI_FILESOURCE, dnd.TYPE_PITIVI_EFFECT]:
+ if targetType not in [dnd.TYPE_PITIVI_FILESOURCE,
+ dnd.TYPE_PITIVI_EFFECT]:
context.finish(False, False, timestamp)
return
@@ -508,12 +509,16 @@ class Timeline(gtk.Table, Loggable, Zoomable):
def _add_temp_source(self):
uris = self.selection_data.split("\n")
- for layer in self.app.projectManager.current.timeline.get_layers():
- if layer.get_priority() != BACKGROUND_PRIORITY:
- break
+ layers = self.timeline.get_layers()
+
+ if layers:
+ layer = layers[0]
+ else:
+ self.error("No layer in the timeline")
+ return
+
for uri in uris:
src = ges.TimelineFileSource(uri)
- src.set_property("priority", 1)
layer.add_object(src)
self._temp_objects.insert(0, src)
@@ -524,7 +529,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
priority = int((y // (LAYER_HEIGHT_EXPANDED + LAYER_SPACING)))
delta = Zoomable.pixelToNs(x)
obj = self._temp_objects[0]
- obj.starting_start = obj.get_property("start")
+ obj.starting_start = obj.props.start
self._move_context.editTo(delta, priority)
## Zooming and Scrolling
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]