diff --git a/data/ui/cliptransformation.ui b/data/ui/cliptransformation.ui index 1609258eeb9d049b09a72262f3e5283c6969dc4d..abc47fc5c639cd9617228b239738e15517f2c521 100644 --- a/data/ui/cliptransformation.ui +++ b/data/ui/cliptransformation.ui @@ -3,12 +3,6 @@ - - -9999999999 - 9999999999 - 1 - 10 - True False @@ -32,6 +26,18 @@ 1 10 + + -9999999999 + 9999999999 + 1 + 10 + + + -99999999 + 99999999 + 0.01 + 1 + True False @@ -63,6 +69,7 @@ 1 position_x_adjustment + 9 True @@ -79,6 +86,7 @@ 1 position_y_adjustment + 9 True @@ -111,6 +119,18 @@ 3 + + + True + False + Rotate: + 0 + + + 0 + 4 + + True @@ -119,6 +139,7 @@ digits width_adjustment + 9 True @@ -134,6 +155,7 @@ end height_adjustment + 9 True @@ -142,6 +164,23 @@ 3 + + + True + True + end + + rotate_adjustment + 2 + 9 + True + + + 1 + 4 + 3 + + True @@ -219,13 +258,13 @@ True True - 3 + 5 0 - 4 + 5 4 diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index b6d7a6257b2c129423deaf7f737d2858319ab8a2..3e2549a9f9f86e789ac448b0255745db4de04f08 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -571,6 +571,7 @@ class TransformationProperties(Gtk.Expander, Loggable): self.spin_buttons = {} self.spin_buttons_handler_ids = {} self.set_label(_("Transformation")) + self.__rotate_effect = None self.builder = Gtk.Builder() self.builder.add_from_file(os.path.join(get_ui_dir(), @@ -626,6 +627,8 @@ class TransformationProperties(Gtk.Expander, Loggable): self.__setup_spin_button("width_spinbtn", "width") self.__setup_spin_button("height_spinbtn", "height") + self.__setup_spin_button("rotate_spinbtn", "angle") + def __get_keyframes_timestamps(self): keyframes_ts = [] for prop in ["posx", "posy", "width", "height"]: @@ -761,6 +764,10 @@ class TransformationProperties(Gtk.Expander, Loggable): for prop in ["posx", "posy", "width", "height"]: self.source.set_child_property(prop, self.source.ui.default_position[prop]) + if self.__rotate_effect: + self._selected_clip.remove(self.__rotate_effect) + self.__update_spin_btn("angle") + self.__update_keyframes_ui() def __get_source_property(self, prop): @@ -779,13 +786,19 @@ class TransformationProperties(Gtk.Expander, Loggable): return res, value except PipelineError: pass + elif prop == "angle": + self.__rotate_effect = self._get_rotate_effect() + if self.__rotate_effect: + return self.__rotate_effect.get_child_property(prop) + else: + return True, 0 return self.source.get_child_property(prop) def _position_cb(self, unused_pipeline, unused_position): if not self.__source_uses_keyframes(): return - for prop in ["posx", "posy", "width", "height"]: + for prop in ["posx", "posy", "width", "height", "angle"]: self.__update_spin_btn(prop) # Keep the overlay stack in sync with the spin buttons values self.app.gui.editor.viewer.overlay_stack.update(self.source) @@ -793,8 +806,14 @@ class TransformationProperties(Gtk.Expander, Loggable): def __source_property_changed_cb(self, unused_source, unused_element, param): self.__update_spin_btn(param.name) - def __update_spin_btn(self, prop): - assert self.source + def __effect_property_changed_cb(self, unused_source, unused_element, param): + self.__update_spin_btn(param.name, False) + + def __update_spin_btn(self, prop, source_prop=True): + if source_prop: + assert self.source + else: + assert self.__rotate_effect try: spin = self.spin_buttons[prop] @@ -802,7 +821,15 @@ class TransformationProperties(Gtk.Expander, Loggable): except KeyError: return - res, value = self.__get_source_property(prop) + if prop == "angle": + self.__rotate_effect = self._get_rotate_effect() + if self.__rotate_effect: + res, value = self.__rotate_effect.get_child_property(prop) + else: + res, value = True, 0 + else: + res, value = self.__get_source_property(prop) + assert res if spin.get_value() != value: # Make sure self._onValueChangedCb doesn't get called here. If that @@ -840,10 +867,19 @@ class TransformationProperties(Gtk.Expander, Loggable): self.warning("Could not get pipeline position") return else: - with self.app.action_log.started("Transformation property change", - finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline), - toplevel=True): - self.source.set_child_property(prop, value) + with self.app.action_log.started( + "Transformation property change", + finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline), + toplevel=True): + if prop == "angle": + if not self._get_rotate_effect(): + self.__rotate_effect = GES.Effect.new("rotate") + self._selected_clip.add(self.__rotate_effect) + self.__rotate_effect.connect("deep-notify", self.__effect_property_changed_cb) + + self.__rotate_effect.set_child_property(prop, value) + else: + self.source.set_child_property(prop, value) def __setup_spin_button(self, widget_name, property_name): """Creates a SpinButton for editing a property value.""" @@ -853,12 +889,16 @@ class TransformationProperties(Gtk.Expander, Loggable): self.spin_buttons[property_name] = spinbtn self.spin_buttons_handler_ids[property_name] = handler_id + def _get_rotate_effect(self): + for effect in self._selected_clip.get_top_effects(): + if effect.props.bin_description == "rotate": + return effect + def _onValueChangedCb(self, spinbtn, prop): if not self.source: return value = spinbtn.get_value() - res, cvalue = self.__get_source_property(prop) if not res: return diff --git a/pitivi/effects.py b/pitivi/effects.py index 9e8c07f66e5064029efe4520da96cb5c80b5c575..497cae4742abfb4a18b45235f3887e4541e9287f 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -99,7 +99,7 @@ VIDEO_EFFECTS_CATEGORIES = ( "cogscale", "aspectratiocrop", "cogdownsample", "videoscale", "videocrop", "videoflip", "videobox", "gdkpixbufscale", "kaleidoscope", "mirror", "pinch", "sphere", "square", "fisheye", - "stretch", "twirl", "waterriple", "rotate", "bulge", "circle", + "stretch", "twirl", "waterriple", "bulge", "circle", "frei0r-filter-letterb0xed", "frei0r-filter-k-means-clustering", "frei0r-filter-lens-correction", "frei0r-filter-defish0r", "frei0r-filter-perspective", "frei0r-filter-c0rners", @@ -142,7 +142,9 @@ BLACKLISTED_PLUGINS = [] HIDDEN_EFFECTS = [ # Overlaying an image onto a video stream can already be done. - "gdkpixbufoverlay"] + "gdkpixbufoverlay", + # This effect was moved to transformation box. + "rotate"] GlobalSettings.addConfigSection('effect-library') diff --git a/tests/test_timeline_elements.py b/tests/test_timeline_elements.py index b0ae2e9ff3e7ea331a5a2d717c9cc8d87c1adcc0..976c19a51f0fcb99869b8a3ffc6b29ac09ac91ab 100644 --- a/tests/test_timeline_elements.py +++ b/tests/test_timeline_elements.py @@ -30,8 +30,8 @@ from matplotlib.backend_bases import MouseEvent from pitivi.timeline.elements import GES_TYPE_UI_TYPE from pitivi.undo.undo import UndoableActionLog from pitivi.utils.timeline import Zoomable -from tests.test_timeline_timeline import BaseTestTimeline from tests import common +from tests.test_timeline_timeline import BaseTestTimeline class TestKeyframeCurve(BaseTestTimeline):