[pitivi] titleeditor: Implement Undo Redo
- From: Thibault Saunier <tsaunier src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] titleeditor: Implement Undo Redo
- Date: Sat, 15 Nov 2014 10:33:25 +0000 (UTC)
commit 89203ef897a98d4f302478d6281394e70dd23570
Author: Thibault Saunier <tsaunier gnome org>
Date: Sat Sep 27 15:04:05 2014 +0200
titleeditor: Implement Undo Redo
Keeping things as simple as possible using the
GES.TrackElement.s[g]et_child_property API everywhere.
https://bugzilla.gnome.org/show_bug.cgi?id=739251
pitivi/project.py | 2 +-
pitivi/titleeditor.py | 160 +++++++++++++++++++++++++++++++++-------------
pitivi/undo/timeline.py | 8 ++-
3 files changed, 123 insertions(+), 47 deletions(-)
---
diff --git a/pitivi/project.py b/pitivi/project.py
index 966615a..bd31804 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -76,7 +76,7 @@ class AssetRemovedAction(UndoableAction):
def serializeLastAction(self):
st = Gst.Structure.new_empty("remove-asset")
- st.set_value("id", self.asset.get_info().get_uri())
+ st.set_value("id", self.asset.get_id())
type_string = GObject.type_name(self.asset.get_extractable_type())
st.set_value("type", type_string)
return st
diff --git a/pitivi/titleeditor.py b/pitivi/titleeditor.py
index 3336867..ec54901 100644
--- a/pitivi/titleeditor.py
+++ b/pitivi/titleeditor.py
@@ -52,6 +52,7 @@ class TitleEditor(Loggable):
def __init__(self, app):
Loggable.__init__(self)
self.app = app
+ self.action_log = app.action_log
self.settings = {}
self.source = None
self.seeker = Seeker()
@@ -59,6 +60,8 @@ class TitleEditor(Loggable):
# Drag attributes
self._drag_events = []
self._signals_connected = False
+ self._setting_props = False
+ self._children_props_handler = None
self._createUI()
@@ -75,7 +78,7 @@ class TitleEditor(Loggable):
self.textbuffer = Gtk.TextBuffer()
self.textarea.set_buffer(self.textbuffer)
- self.textbuffer.connect("changed", self._updateSourceText)
+ self.textbuffer.connect("changed", self._textChangedCb)
self.font_button = builder.get_object("fontbutton1")
self.foreground_color_button = builder.get_object("fore_text_color")
@@ -99,25 +102,29 @@ class TitleEditor(Loggable):
self.settings["halignment"].append(en, n)
self._deactivate()
+ def _setChildProperty(self, name, value):
+ self.action_log.begin("Title %s change" % name)
+ self._setting_props = True
+ self.source.set_child_property(name, value)
+ self._setting_props = False
+ self.action_log.commit()
+
def _backgroundColorButtonCb(self, widget):
color = gdk_rgba_to_argb(widget.get_rgba())
self.debug("Setting title background color to %x", color)
- self.source.set_background(color)
- self.seeker.flush()
+ self._setChildProperty("foreground-color", color)
def _frontTextColorButtonCb(self, widget):
color = gdk_rgba_to_argb(widget.get_rgba())
self.debug("Setting title foreground color to %x", color)
# TODO: Use set_text_color when we work with TitleSources instead of
# TitleClips
- self.source.set_color(color)
- self.seeker.flush()
+ self._setChildProperty("color", color)
def _fontButtonCb(self, widget):
font_desc = widget.get_font_desc().to_string()
self.debug("Setting font desc to %s", font_desc)
- self.source.set_font_desc(font_desc)
- self.seeker.flush()
+ self._setChildProperty("font-desc", font_desc)
def _activate(self):
"""
@@ -137,13 +144,15 @@ class TitleEditor(Loggable):
self.editing_box.hide()
self._disconnect_signals()
- def _updateFromSource(self):
- if not self.source:
- # Nothing to update from.
- return
+ def _setWidgetText(self):
+ res, source_text = self.source.get_child_property("text")
+ text = self.textbuffer.get_text(self.textbuffer.get_start_iter(),
+ self.textbuffer.get_end_iter(),
+ True)
+ if text == source_text:
+ return False
- source_text = self.source.get_text()
- if source_text is None:
+ if res is False:
# FIXME: sometimes we get a TextOverlay/TitleSource
# without a valid text property. This should not happen.
source_text = ""
@@ -152,24 +161,32 @@ class TitleEditor(Loggable):
self.log("Title text set to %s", source_text)
self.textbuffer.set_text(source_text)
- self.settings['xpos'].set_value(self.source.get_xpos())
- self.settings['ypos'].set_value(self.source.get_ypos())
+ return True
+
+ def _updateFromSource(self):
+ if not self.source:
+ # Nothing to update from.
+ return
+
+ self._setWidgetText()
+ self.settings['xpos'].set_value(self.source.get_child_property("xpos")[1])
+ self.settings['ypos'].set_value(self.source.get_child_property("ypos")[1])
self.settings['valignment'].set_active_id(
- self.source.get_valignment().value_name)
+ self.source.get_child_property("valignment")[1].value_name)
self.settings['halignment'].set_active_id(
- self.source.get_halignment().value_name)
+ self.source.get_child_property("halignment")[1].value_name)
font_desc = Pango.FontDescription.from_string(
- self.source.get_font_desc())
+ self.source.get_child_property("font-desc")[1])
self.font_button.set_font_desc(font_desc)
- color = argb_to_gdk_rgba(self.source.get_text_color())
+ color = argb_to_gdk_rgba(self.source.get_child_property("color")[1])
self.foreground_color_button.set_rgba(color)
- color = argb_to_gdk_rgba(self.source.get_background_color())
+ color = argb_to_gdk_rgba(self.source.get_child_property("foreground-color")[1])
self.background_color_button.set_rgba(color)
- def _updateSourceText(self, unused_updated_obj):
+ def _textChangedCb(self, unused_updated_obj):
if not self.source:
# Nothing to update.
return
@@ -178,8 +195,7 @@ class TitleEditor(Loggable):
self.textbuffer.get_end_iter(),
True)
self.log("Source text updated to %s", text)
- self.source.set_text(text)
- self.seeker.flush()
+ self._setChildProperty("text", text)
def _updateSource(self, updated_obj):
"""
@@ -192,22 +208,17 @@ class TitleEditor(Loggable):
for name, obj in list(self.settings.items()):
if obj == updated_obj:
if name == "valignment":
- self.source.set_valignment(
- getattr(GES.TextVAlign, obj.get_active_id().upper()))
- self.settings["ypos"].set_visible(
- obj.get_active_id() == "position")
+ value = getattr(GES.TextVAlign, obj.get_active_id().upper())
+ visible = obj.get_active_id() == "position"
+ self.settings["ypos"].set_visible(visible)
elif name == "halignment":
- self.source.set_halignment(
- getattr(GES.TextHAlign, obj.get_active_id().upper()))
- self.settings["xpos"].set_visible(
- obj.get_active_id() == "position")
- elif name == "xpos":
- self.settings["halignment"].set_active_id("position")
- self.source.set_xpos(obj.get_value())
- elif name == "ypos":
- self.settings["valignment"].set_active_id("position")
- self.source.set_ypos(obj.get_value())
- self.seeker.flush()
+ value = getattr(GES.TextHAlign, obj.get_active_id().upper())
+ visible = obj.get_active_id() == "position"
+ self.settings["xpos"].set_visible(visible)
+ else:
+ value = obj.get_value()
+
+ self._setChildProperty(name, value)
return
def set_source(self, source):
@@ -220,14 +231,13 @@ class TitleEditor(Loggable):
self._deactivate()
assert isinstance(source, GES.TextOverlay) or \
isinstance(source, GES.TitleSource)
- # TODO: Remove ".get_parent()" when bug 727880 is fixed.
- self.source = source.get_parent()
+ self.source = source
self._updateFromSource()
self._activate()
def unset_source(self):
- self.source = None
self._deactivate()
+ self.source = None
def _createCb(self, unused_button):
"""
@@ -236,14 +246,68 @@ class TitleEditor(Loggable):
clip = GES.TitleClip()
clip.set_text("")
clip.set_duration(int(Gst.SECOND * 5))
- clip.set_color(FOREGROUND_DEFAULT_COLOR)
- clip.set_background(BACKGROUND_DEFAULT_COLOR)
# TODO: insert on the current layer at the playhead position.
# If no space is available, create a new layer to insert to on top.
self.app.gui.timeline_ui.insertEnd([clip])
self.app.gui.timeline_ui.timeline.selection.setToObj(clip, SELECT)
+ clip.set_color(FOREGROUND_DEFAULT_COLOR)
+ clip.set_background(BACKGROUND_DEFAULT_COLOR)
+
+ def _propertyChangedCb(self, source, unused_gstelement, pspec):
+ if self._setting_props:
+ self.seeker.flush()
+ return
+
+ flush = False
+ if pspec.name == "text":
+ if self._setWidgetText() is True:
+ flush = True
+ elif pspec.name in ["xpos", "ypos"]:
+ value = self.source.get_child_property(pspec.name)[1]
+ if self.settings[pspec.name].get_value() == value:
+ return
+
+ flush = True
+ self.settings[pspec.name].set_value(value)
+ elif pspec.name in ["valignment", "halignment"]:
+ value = self.source.get_child_property(pspec.name)[1].value_name
+ if self.settings[pspec.name].get_active_id() == value:
+ return
+
+ flush = True
+ self.settings[pspec.name].set_active_id(value)
+ elif pspec.name == "font-desc":
+ value = self.source.get_child_property("font-desc")[1]
+ if self.font_button.get_font_desc() == value:
+ return
+
+ flush = True
+ font_desc = Pango.FontDescription.from_string(value)
+ self.font_button.set_font_desc(font_desc)
+ elif pspec.name == "color":
+ color = argb_to_gdk_rgba(self.source.get_child_property("color")[1])
+ if color == self.foreground_color_button.get_rgba():
+ return
+
+ flush = True
+ self.foreground_color_button.set_rgba(color)
+ elif pspec.name == "foreground-color":
+ color = argb_to_gdk_rgba(self.source.get_child_property("foreground-color")[1])
+
+ if color == self.background_color_button.get_rgba():
+ return
+
+ flush = True
+ self.background_color_button.set_rgba(color)
+
+ if flush is True:
+ self.seeker.flush()
+
def _connect_signals(self):
+ if self.source and not self._children_props_handler:
+ self._children_props_handler = self.source.connect('deep-notify',
+ self._propertyChangedCb)
if not self._signals_connected:
self.app.gui.viewer.target.connect(
"motion-notify-event", self.drag_notify_event)
@@ -254,6 +318,10 @@ class TitleEditor(Loggable):
self._signals_connected = True
def _disconnect_signals(self):
+ if self._children_props_handler is not None:
+ self.source.disconnect(self._children_props_handler)
+ self._children_props_handler = None
+
if not self._signals_connected:
return
self.app.gui.viewer.target.disconnect_by_func(self.drag_notify_event)
@@ -295,7 +363,6 @@ class TitleEditor(Loggable):
newypos = self.settings["ypos"].get_value() + ydiff
self.settings["xpos"].set_value(newxpos)
self.settings["ypos"].set_value(newypos)
- self.seeker.flush()
return True
else:
return False
@@ -318,7 +385,10 @@ class TitleEditor(Loggable):
def selectionChangedCb(self, selection):
selected_clip = selection.getSingleClip(GES.TitleClip)
- source = selected_clip and selected_clip.get_children(False)[0]
+ source = None
+ if selected_clip:
+ source = selected_clip.get_children(False)[0]
+
if source:
self.set_source(source)
else:
diff --git a/pitivi/undo/timeline.py b/pitivi/undo/timeline.py
index e4845bf..319716c 100644
--- a/pitivi/undo/timeline.py
+++ b/pitivi/undo/timeline.py
@@ -50,7 +50,11 @@ class TrackElementPropertyChanged(UndoableAction):
st = Gst.Structure.new_empty("set-child-property")
st['element-name'] = self.track_element.get_name()
st['property'] = self.property_name
- st['value'] = self.new_value
+ value = self.new_value
+ if isinstance(self.new_value, GObject.GFlags) or\
+ isinstance(self.new_value, GObject.GEnum):
+ value = int(self.new_value)
+ st['value'] = value
return st
@@ -527,6 +531,8 @@ class TimelineLogObserver(object):
# self._connectToInterpolator(interpolator)
if isinstance(track_element, GES.BaseEffect):
self.children_props_tracker.addTrackElement(track_element)
+ elif isinstance(track_element, GES.TitleSource):
+ self.children_props_tracker.addTrackElement(track_element)
def _disconnectFromTrackElement(self, track_element):
pass
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]