[pitivi] Reimplement the transformation box



commit 45ea0377618660efabf0982d595f16849766f9f0
Author: Thibault Saunier <tsaunier gnome org>
Date:   Sat Jun 13 18:35:09 2015 +0200

    Reimplement the transformation box
    
    Summary:
    For the time being there is no visual indicator, but the
    user can manipulate the video in the viewer with the
    following shortcut:
      * Dragging the  in the viewer while a clip is selected at the current
        playback position will move the image
      * Scrolling in the viewer in the same condition will 'zoom in/out'
        meaning that it will actually changed the size of the video, keeping
        aspect ratio
      * Scrolling with the shift modifier will change the height
      * Scrolling with the control modifier will change the width
    
    Depends on D267
    
    Reviewers: Mathieu_Du, aleb
    
    Differential Revision: https://phabricator.freedesktop.org/D268

 data/ui/cliptransformation.ui |  235 ++++------------------------------------
 pitivi/clipproperties.py      |  155 +++++++++++----------------
 pitivi/viewer.py              |  122 ++++++++++++++++++++--
 3 files changed, 200 insertions(+), 312 deletions(-)
---
diff --git a/data/ui/cliptransformation.ui b/data/ui/cliptransformation.ui
index 86553e2..1035f20 100644
--- a/data/ui/cliptransformation.ui
+++ b/data/ui/cliptransformation.ui
@@ -2,64 +2,29 @@
 <!-- Generated with glade 3.18.3 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
-  <object class="GtkAdjustment" id="crop_bottom_adjustment">
-    <property name="upper">1</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
-  </object>
-  <object class="GtkAdjustment" id="crop_left_adjustment">
-    <property name="upper">1</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
-  </object>
-  <object class="GtkAdjustment" id="crop_right_adjustment">
-    <property name="upper">1</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
-  </object>
-  <object class="GtkAdjustment" id="crop_top_adjustment">
-    <property name="upper">1</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
-  </object>
   <object class="GtkAdjustment" id="height_adjustment">
-    <property name="upper">100</property>
-    <property name="value">0.5</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
+    <property name="lower">-9999999999</property>
+    <property name="upper">9999999999</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
   </object>
   <object class="GtkAdjustment" id="position_x_adjustment">
-    <property name="lower">-1</property>
-    <property name="upper">2</property>
-    <property name="value">0.5</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
+    <property name="lower">-9999999999</property>
+    <property name="upper">9999999999</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
   </object>
   <object class="GtkAdjustment" id="position_y_adjustment">
-    <property name="lower">-1</property>
-    <property name="upper">2</property>
-    <property name="value">0.5</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
-  </object>
-  <object class="GtkAdjustment" id="rotation_adjustment">
-    <property name="lower">-999.99000000000001</property>
-    <property name="upper">999.99000000000001</property>
+    <property name="lower">-9999999999</property>
+    <property name="upper">9999999999</property>
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
   <object class="GtkAdjustment" id="width_adjustment">
-    <property name="upper">100</property>
-    <property name="value">0.5</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
-  </object>
-  <object class="GtkAdjustment" id="zoom_adjustment">
-    <property name="lower">0.10000000000000001</property>
-    <property name="upper">1</property>
-    <property name="value">1</property>
-    <property name="step_increment">0.01</property>
-    <property name="page_increment">0.10000000000000001</property>
+    <property name="lower">-9999999999</property>
+    <property name="upper">9999999999</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
   </object>
   <object class="GtkBox" id="transform_box">
     <property name="visible">True</property>
@@ -96,45 +61,6 @@
       </packing>
     </child>
     <child>
-      <object class="GtkFrame" id="frame4">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="label_xalign">0</property>
-        <property name="shadow_type">none</property>
-        <child>
-          <object class="GtkAlignment" id="alignment4">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="left_padding">12</property>
-            <child>
-              <object class="GtkScale" id="zoom_scale">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="adjustment">zoom_adjustment</property>
-                <property name="round_digits">1</property>
-                <property name="draw_value">False</property>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child type="label">
-          <object class="GtkLabel" id="label6">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="label" translatable="yes">Viewer Zoom</property>
-            <attributes>
-              <attribute name="weight" value="bold"/>
-            </attributes>
-          </object>
-        </child>
-      </object>
-      <packing>
-        <property name="expand">True</property>
-        <property name="fill">True</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
-    <child>
       <object class="GtkFrame" id="frame3">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
@@ -167,8 +93,8 @@
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="invisible_char">•</property>
+                    <property name="progress_pulse_step">1</property>
                     <property name="adjustment">position_x_adjustment</property>
-                    <property name="digits">2</property>
                     <property name="numeric">True</property>
                   </object>
                   <packing>
@@ -194,8 +120,8 @@
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="invisible_char">•</property>
+                    <property name="progress_pulse_step">1</property>
                     <property name="adjustment">position_y_adjustment</property>
-                    <property name="digits">2</property>
                     <property name="numeric">True</property>
                   </object>
                   <packing>
@@ -258,8 +184,8 @@
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="invisible_char">•</property>
+                    <property name="input_purpose">digits</property>
                     <property name="adjustment">width_adjustment</property>
-                    <property name="digits">2</property>
                     <property name="numeric">True</property>
                   </object>
                   <packing>
@@ -286,7 +212,6 @@
                     <property name="can_focus">True</property>
                     <property name="invisible_char">•</property>
                     <property name="adjustment">height_adjustment</property>
-                    <property name="digits">2</property>
                     <property name="numeric">True</property>
                   </object>
                   <packing>
@@ -316,124 +241,12 @@
         <property name="position">3</property>
       </packing>
     </child>
-    <child>
-      <object class="GtkFrame" id="frame2">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="label_xalign">0</property>
-        <property name="shadow_type">none</property>
-        <child>
-          <object class="GtkAlignment" id="alignment2">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="xalign">0</property>
-            <property name="xscale">0</property>
-            <child>
-              <object class="GtkGrid" id="grid1">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="row_spacing">3</property>
-                <property name="column_spacing">3</property>
-                <child>
-                  <object class="GtkSpinButton" id="crop_left_spinbtn">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="invisible_char">•</property>
-                    <property name="adjustment">crop_left_adjustment</property>
-                    <property name="digits">2</property>
-                    <property name="numeric">True</property>
-                  </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSpinButton" id="crop_top_spinbtn">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="invisible_char">•</property>
-                    <property name="adjustment">crop_top_adjustment</property>
-                    <property name="digits">2</property>
-                    <property name="numeric">True</property>
-                  </object>
-                  <packing>
-                    <property name="left_attach">2</property>
-                    <property name="top_attach">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSpinButton" id="crop_bottom_spinbtn">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="invisible_char">•</property>
-                    <property name="adjustment">crop_bottom_adjustment</property>
-                    <property name="digits">2</property>
-                    <property name="numeric">True</property>
-                  </object>
-                  <packing>
-                    <property name="left_attach">2</property>
-                    <property name="top_attach">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSpinButton" id="crop_right_spinbtn">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="invisible_char">•</property>
-                    <property name="adjustment">crop_right_adjustment</property>
-                    <property name="digits">2</property>
-                    <property name="numeric">True</property>
-                  </object>
-                  <packing>
-                    <property name="left_attach">3</property>
-                    <property name="top_attach">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <placeholder/>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child type="label">
-          <object class="GtkLabel" id="label2">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="label" translatable="yes">Crop</property>
-            <attributes>
-              <attribute name="weight" value="bold"/>
-            </attributes>
-          </object>
-        </child>
-      </object>
-      <packing>
-        <property name="expand">False</property>
-        <property name="fill">True</property>
-        <property name="position">4</property>
-      </packing>
-    </child>
+  </object>
+  <object class="GtkAdjustment" id="zoom_adjustment">
+    <property name="lower">0.10000000000000001</property>
+    <property name="upper">1</property>
+    <property name="value">1</property>
+    <property name="step_increment">0.01</property>
+    <property name="page_increment">0.10000000000000001</property>
   </object>
 </interface>
diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py
index d33ffbf..a8c2c50 100644
--- a/pitivi/clipproperties.py
+++ b/pitivi/clipproperties.py
@@ -30,8 +30,6 @@ from gettext import gettext as _
 
 from pitivi.configure import get_ui_dir
 
-from pitivi.dialogs.depsmanager import DepsManager
-
 from pitivi.utils.ui import EFFECT_TARGET_ENTRY
 from pitivi.utils.loggable import Loggable
 from pitivi.utils.ui import PADDING, SPACING
@@ -74,10 +72,10 @@ class ClipProperties(Gtk.Box, Loggable):
         self.infobar_box.show()
         self.pack_start(self.infobar_box, False, False, 0)
 
-        # Transformation boxed DISABLED
-        # self.transformation_expander = TransformationProperties(instance, instance.action_log)
-        # self.transformation_expander.set_vexpand(False)
-        # vbox.pack_start(self.transformation_expander, False, False, 0)
+        self.transformation_expander = TransformationProperties(app, app.action_log)
+        self.transformation_expander.set_vexpand(False)
+        self.pack_start(self.transformation_expander, False, False, 0)
+        self.transformation_expander.show_all()
 
         effects_properties_manager = EffectsPropertiesManager(app)
         self.effect_expander = EffectProperties(
@@ -95,9 +93,8 @@ class ClipProperties(Gtk.Box, Loggable):
         if project:
             self.effect_expander._connectTimelineSelection(
                 self.app.gui.timeline_ui.timeline)
-            # Transformation boxed DISABLED
-            # if self.transformation_expander:
-            #     self.transformation_expander.timeline = self.app.gui.timeline_ui.timeline
+            if self.transformation_expander:
+                self.transformation_expander.timeline = self.app.gui.timeline_ui.timeline
 
     def _getProject(self):
         return self._project
@@ -192,8 +189,8 @@ class EffectProperties(Gtk.Expander, Loggable):
         activatedcell = Gtk.CellRendererToggle()
         activatedcell.props.xpad = PADDING
         activatedcell.connect("toggled", self._effectActiveToggleCb)
-        activatedcol = self.treeview.insert_column_with_attributes(-1,
-                                                                   _("Active"), activatedcell, 
active=COL_ACTIVATED)
+        self.treeview.insert_column_with_attributes(-1,
+                                                    _("Active"), activatedcell, active=COL_ACTIVATED)
 
         typecol = Gtk.TreeViewColumn(_("Type"))
         typecol.set_spacing(SPACING)
@@ -551,7 +548,7 @@ class EffectProperties(Gtk.Expander, Loggable):
         self._effect_config_ui.show_all()
 
 
-class TransformationProperties(Gtk.Expander):
+class TransformationProperties(Gtk.Expander, Loggable):
     """
     Widget for viewing and configuring speed
     """
@@ -561,9 +558,11 @@ class TransformationProperties(Gtk.Expander):
 
     def __init__(self, app, action_log):
         Gtk.Expander.__init__(self)
+        Loggable.__init__(self)
         self.action_log = action_log
         self.app = app
         self._timeline = None
+        self.source = None
         self._selected_clip = None
         self.spin_buttons = {}
         self.default_values = {}
@@ -580,59 +579,55 @@ class TransformationProperties(Gtk.Expander):
         self.hide()
 
     def _initButtons(self):
-        self.zoom_scale = self.builder.get_object("zoom_scale")
-        self.zoom_scale.connect("value-changed", self._zoomViewerCb)
         clear_button = self.builder.get_object("clear_button")
         clear_button.connect("clicked", self._defaultValuesCb)
 
-        self._getAndConnectToEffect("xpos_spinbtn", "tilt_x")
-        self._getAndConnectToEffect("ypos_spinbtn", "tilt_y")
+        self.__setupSpinButton("xpos_spinbtn", "posx")
+        self.__setupSpinButton("ypos_spinbtn", "posy")
 
-        self._getAndConnectToEffect("width_spinbtn", "scale_x")
-        self._getAndConnectToEffect("height_spinbtn", "scale_y")
-
-        self._getAndConnectToEffect("crop_left_spinbtn", "clip_left")
-        self._getAndConnectToEffect("crop_right_spinbtn", "clip_right")
-        self._getAndConnectToEffect("crop_top_spinbtn", "clip_top")
-        self._getAndConnectToEffect("crop_bottom_spinbtn", "clip_bottom")
-        self.connectSpinButtonsToFlush()
+        self.__setupSpinButton("width_spinbtn", "width")
+        self.__setupSpinButton("height_spinbtn", "height")
 
     def _zoomViewerCb(self, scale):
         self.app.gui.viewer.setZoom(scale.get_value())
 
     def _expandedCb(self, expander, params):
         if self._selected_clip:
-            self.effect = self._findOrCreateEffect("frei0r-filter-scale0tilt")
-            self._updateSpinButtons()
+            self.source = self._selected_clip.find_track_element(None,
+                                                                 GES.VideoSource)
+            self.__setSource()
             self.set_expanded(self.get_expanded())
-            self._updateBoxVisibility()
-            self.zoom_scale.set_value(1.0)
         else:
-            if self.get_expanded():
-                DepsManager(self.app)
             self.set_expanded(False)
 
     def _defaultValuesCb(self, widget):
-        self.disconnectSpinButtonsFromFlush()
         for name, spinbtn in list(self.spin_buttons.items()):
             spinbtn.set_value(self.default_values[name])
-        self.connectSpinButtonsToFlush()
-        # FIXME Why are we looking at the gnl object directly?
-        self.effect.gnl_object.props.active = False
 
-    def disconnectSpinButtonsFromFlush(self):
-        for spinbtn in list(self.spin_buttons.values()):
-            spinbtn.disconnect_by_func(self._flushPipeLineCb)
+    def __sourcePropertyChangedCb(self, source, element, param):
+        try:
+            spin = self.spin_buttons[param.name]
+        except KeyError:
+            return
 
-    def connectSpinButtonsToFlush(self):
-        for spinbtn in list(self.spin_buttons.values()):
-            spinbtn.connect("output", self._flushPipeLineCb)
+        res, value = self.source.get_child_property(param.name)
+        if spin.get_value() != value:
+            spin.set_value(value)
 
     def _updateSpinButtons(self):
         for name, spinbtn in list(self.spin_buttons.items()):
-            spinbtn.set_value(self.effect.get_property(name))
+            res, value = self.source.get_child_property(name)
+            assert(res)
+            if name == "width":
+                self.default_values[name] = self.app.project_manager.current_project.videowidth
+            elif name == "height":
+                self.default_values[name] = self.app.project_manager.current_project.videoheight
+            else:
+                self.default_values[name] = 0
+            spinbtn.set_value(value)
+            self.source.connect("deep-notify", self.__sourcePropertyChangedCb)
 
-    def _getAndConnectToEffect(self, widget_name, property_name):
+    def __setupSpinButton(self, widget_name, property_name):
         """
         Create a spinbutton widget and connect its signals to change property
         values. While focused, disable the timeline actions' sensitivity.
@@ -640,88 +635,60 @@ class TransformationProperties(Gtk.Expander):
         spinbtn = self.builder.get_object(widget_name)
         spinbtn.connect("output", self._onValueChangedCb, property_name)
         self.spin_buttons[property_name] = spinbtn
-        self.default_values[property_name] = spinbtn.get_value()
 
     def _onValueChangedCb(self, spinbtn, prop):
-        value = spinbtn.get_value()
+        if not self.source:
+            return
 
-        # FIXME Why are we looking at the gnl object directly?
-        if value != self.default_values[prop] and not self.effect.get_gnlobject().props.active:
-            self.effect.get_gnlobject().props.active = True
+        value = spinbtn.get_value()
 
-        if value != self.effect.get_property(prop):
+        res, cvalue = self.source.get_child_property(prop)
+        if value != cvalue:
             self.action_log.begin("Transformation property change")
-            self.effect.set_property(prop, value)
+            self.source.set_child_property(prop, value)
             self.action_log.commit()
-        box = self.app.gui.viewer.internal.box
+            self.app.project_manager.current_project.pipeline.commit_timeline()
 
-        # update box when values are changed in the spin boxes,
-        # so no point is selected
-        if box and box.clicked_point == 0:
-            box.update_from_effect(self.effect)
-
-    def _flushPipeLineCb(self, widget):
-        self.app.project_manager.current_project.pipeline.flushSeek()
+    def __setSource(self):
+        if self.source:
+            try:
+                self.source.disconnect_by_func(self.__sourcePropertyChangedCb)
+            except TypeError:
+                pass
+        if self.get_expanded() and self._selected_clip:
+            self.source = self._selected_clip.find_track_element(None,
+                                                                 GES.VideoSource)
 
-    def _findEffect(self, name):
-        for effect in self._selected_clip.get_children(False):
-            if isinstance(effect, GES.BaseEffect):
-                if name in effect.get_property("bin-description"):
-                    self.effect = effect
-                    return effect.get_element()
-
-    def _findOrCreateEffect(self, name):
-        effect = self._findEffect(name)
-        if not effect:
-            effect = GES.Effect.new(bin_description=name)
-            self._selected_clip.add(effect)
-            tracks = self.app.project_manager.current_project.timeline.get_tracks(
-            )
-            effect = self._findEffect(name)
-            # disable the effect on default
-            a = self.effect.get_gnlobject()
-            self.effect = list(list(a.elements())[0].elements())[1]
-            self.effect.get_gnlobject().props.active = False
-        self.app.gui.viewer.internal.set_transformation_properties(self)
-        effect.freeze_notify()
-        return self.effect
+            self._updateSpinButtons()
+        else:
+            self.source = None
 
     def _selectionChangedCb(self, timeline):
         if self.timeline and len(self.timeline.selection.selected) > 0:
             # choose last selected clip
-            # TODO: hide effects properties when multiple clips are selected
+            # TODO: hide source properties when multiple clips are selected
             for clip in self.timeline.selection.selected:
                 pass
 
             if clip != self._selected_clip:
                 self._selected_clip = clip
-                self.effect = None
 
             self.show()
-            if self.get_expanded():
-                self.effect = self._findOrCreateEffect(
-                    "frei0r-filter-scale0tilt")
-                self._updateSpinButtons()
+            self.__setSource()
         else:
             # Deselect
             if self._selected_clip:
                 self._selected_clip = None
-                self.zoom_scale.set_value(1.0)
                 self.app.project_manager.current_project.pipeline.flushSeek()
-            self.effect = None
+            self.__setSource()
             self.hide()
-        self._updateBoxVisibility()
-
-    def _updateBoxVisibility(self):
-        if self.get_expanded() and self._selected_clip:
-            self.app.gui.viewer.internal.show_box()
-        else:
-            self.app.gui.viewer.internal.hide_box()
 
     def _getTimeline(self):
         return self._timeline
 
     def _setTimeline(self, timeline):
+        if self.timeline:
+            self.timeline.selection.disconnect_by_func(self._selectionChangedCb)
         self._timeline = timeline
         if timeline:
             self._timeline.selection.connect(
diff --git a/pitivi/viewer.py b/pitivi/viewer.py
index 0efca82..ed02a74 100644
--- a/pitivi/viewer.py
+++ b/pitivi/viewer.py
@@ -24,17 +24,15 @@ from gi.repository import Gdk
 from gi.repository import Gst
 from gi.repository import GObject
 from gi.repository import GES
-import cairo
 
 from gettext import gettext as _
 from time import time
-from math import pi
 
 from pitivi.settings import GlobalSettings
 from pitivi.utils.loggable import Loggable
 from pitivi.utils.misc import format_ns
 from pitivi.utils.pipeline import AssetPipeline, Seeker
-from pitivi.utils.ui import SPACING, hex_to_rgb
+from pitivi.utils.ui import SPACING
 from pitivi.utils.widgets import TimeWidget
 
 GlobalSettings.addConfigSection("viewer")
@@ -141,7 +139,7 @@ class ViewerContainer(Gtk.Box, Loggable):
         self.sink.props.sink = Gst.ElementFactory.make("gtkglsink", None)
         self.pipeline.setSink(self.sink)
 
-        self.target = ViewerWidget(self.sink, self.app.settings)
+        self.target = ViewerWidget(self.sink, self.app)
 
         if self.docked:
             self.pack_start(self.target, True, True, 0)
@@ -480,6 +478,109 @@ class ViewerContainer(Gtk.Box, Loggable):
             self.system.uninhibitScreensaver(self.INHIBIT_REASON)
 
 
+class TransformationBox(Gtk.EventBox, Loggable):
+    def __init__(self, app):
+        Gtk.EventBox.__init__(self)
+        Loggable.__init__(self)
+
+        self.app = app
+        self.__editSource = None
+        self.__startDraggingPosition = None
+        self.add_events(Gdk.EventMask.SCROLL_MASK)
+
+    def __setupEditSource(self):
+        if self.__editSource:
+            return
+        elif self.app.project_manager.current_project.pipeline.getState() != Gst.State.PAUSED:
+            return
+
+        try:
+            position = self.app.project_manager.current_project.pipeline.getPosition()
+        except:
+            return False
+
+        self.__editSource = None
+        for clip in self.app.project_manager.current_project.timeline.ui.selection.selected:
+            if clip.props.start <= position and position <= clip.props.start + clip.props.duration:
+                video_source = clip.find_track_elements(None, GES.TrackType.VIDEO, GES.VideoSource)
+                if video_source and self.__editSource:
+                    video_source = None
+                    break
+
+                try:
+                    self.__editSource = video_source[0]
+                except IndexError:
+                    continue
+
+    def do_event(self, event):
+        if event.type == Gdk.EventType.ENTER_NOTIFY and event.mode == Gdk.CrossingMode.NORMAL:
+            self.__setupEditSource()
+            if self.__editSource:
+                self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.HAND1))
+        elif event.type == Gdk.EventType.BUTTON_RELEASE:
+            self.__startDraggingPosition = None
+        elif event.type == Gdk.EventType.LEAVE_NOTIFY and event.mode == Gdk.CrossingMode.NORMAL:
+            self.get_window().set_cursor(None)
+            self.__startDraggingPosition = None
+            self.__editSource = None
+            self.__startEditSourcePosition = None
+        elif event.type == Gdk.EventType.BUTTON_PRESS:
+            self.__setupEditSource()
+            if self.__editSource:
+                res_x, current_x = self.__editSource.get_child_property("posx")
+                res_y, current_y = self.__editSource.get_child_property("posy")
+
+                if res_x and res_y:
+                    event_widget = Gtk.get_event_widget(event)
+                    x, y = event_widget.translate_coordinates(self, event.x, event.y)
+                    self.__startEditSourcePosition = (current_x, current_y)
+                    self.__startDraggingPosition = (x, y)
+        elif event.type == Gdk.EventType.MOTION_NOTIFY:
+            if self.__startDraggingPosition and self.__editSource:
+                event_widget = Gtk.get_event_widget(event)
+                x, y = event_widget.translate_coordinates(self, event.x, event.y)
+                self.__editSource.set_child_property("posx",
+                                                     self.__startEditSourcePosition[0] +
+                                                     (x - self.__startDraggingPosition[0]))
+
+                self.__editSource.set_child_property("posy", self.__startEditSourcePosition[1] +
+                                                     (y - self.__startDraggingPosition[1]))
+                self.app.project_manager.current_project.pipeline.commit_timeline()
+        elif event.type == Gdk.EventType.SCROLL:
+            if self.__editSource:
+                res, delta_x, delta_y = event.get_scroll_deltas()
+                if not res:
+                    res, direction = event.get_scroll_direction()
+                    if not res:
+                        self.error("Could not get scroll delta")
+                        return True
+
+                    if direction == Gdk.ScrollDirection.UP:
+                        delta_y = -1.0
+                    elif direction == Gdk.ScrollDirection.DOWN:
+                        delta_y = 1.0
+                    else:
+                        self.error("Could not handle %s scroll event" % direction)
+                        return True
+
+                delta_y = delta_y * -1.0
+                width = self.__editSource.get_child_property("width")[1]
+                height = self.__editSource.get_child_property("height")[1]
+                if event.get_state()[1] & Gdk.ModifierType.SHIFT_MASK:
+                    height += delta_y
+                elif event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK:
+                    width += delta_y
+                else:
+                    width += delta_y
+                    height += delta_y
+
+                self.__editSource.set_child_property("width", width)
+                self.__editSource.set_child_property("height", height)
+                self.app.project_manager.current_project.pipeline.commit_timeline()
+
+        return True
+
+
 class ViewerWidget(Gtk.AspectFrame, Loggable):
 
     """
@@ -491,24 +592,28 @@ class ViewerWidget(Gtk.AspectFrame, Loggable):
 
     __gsignals__ = {}
 
-    def __init__(self, sink, settings=None):
+    def __init__(self, sink, app=None):
         # Prevent black frames and flickering while resizing or changing focus:
         # The aspect ratio gets overridden by setDisplayAspectRatio.
         Gtk.AspectFrame.__init__(self, xalign=0.5, yalign=0.5,
                                  ratio=4.0 / 3.0, obey_child=False)
         Loggable.__init__(self)
+        self.__transformationBox = TransformationBox(app)
 
         # We only work with a gtkglsink inside a glsinkbin
         self.drawing_area = sink.props.sink.props.widget
 
         # We keep the ViewerWidget hidden initially, or the desktop wallpaper
         # would show through the non-double-buffered widget!
-        self.add(self.drawing_area)
+        self.add(self.__transformationBox)
+        self.__transformationBox.add(self.drawing_area)
 
         self.drawing_area.show()
 
         self.seeker = Seeker()
-        self.settings = settings
+        if app:
+            self.settings = app.settings
+        self.app = app
         self.box = None
         self.stored = False
         self.area = None
@@ -518,6 +623,9 @@ class ViewerWidget(Gtk.AspectFrame, Loggable):
         self.pipeline = None
         self.transformation_properties = None
         self._setting_ratio = False
+        self.__startDraggingPosition = None
+        self.__startEditSourcePosition = None
+        self.__editSource = None
 
     def setDisplayAspectRatio(self, ratio):
         self._setting_ratio = True


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