SHARE
TWEET

Untitled

a guest Feb 21st, 2020 78 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. class StartDurationProperties(Gtk.Expander, Loggable):
  2.     """Widget for configuring the placement and size of the clip."""
  3.  
  4.     __signals__ = {
  5.         'selection-changed': []}
  6.  
  7.     def __init__(self, app):
  8.         Gtk.Expander.__init__(self)
  9.         Loggable.__init__(self)
  10.         self.settings = {}
  11.         self.app = app
  12.         self._project = None
  13.         self._selection = None
  14.         self.source = None
  15.         self._selected_clip = None
  16.         self.spin_buttons = {}
  17.         self.spin_buttons_handler_ids = {}
  18.         self.set_label(_("Start/Duration"))
  19.  
  20.         self.builder = Gtk.Builder()
  21.         self.builder.add_from_file(os.path.join(get_ui_dir(),
  22.                                                 "cliplength.ui"))
  23.         self.__control_bindings = {}
  24.         # Used to make sure self.__control_bindings_changed doesn't get called
  25.         # when bindings are changed from this class
  26.         self.__own_bindings_change = False
  27.         self.add(self.builder.get_object("start_duration_box"))
  28.         self._init_buttons()
  29.         self._init_box_spinners()
  30.         self.show_all()
  31.         self.hide()
  32.  
  33.         self.app.project_manager.connect_after(
  34.             "new-project-loaded", self._new_project_loaded_cb)
  35.         self.app.project_manager.connect_after(
  36.             "project-closed", self.__project_closed_cb)
  37.  
  38.     def _new_project_loaded_cb(self, unused_app, project):
  39.         if self._selection is not None:
  40.             self._selection.disconnect_by_func(self._selection_changed_cb)
  41.             self._selection = None
  42.         if self._project:
  43.             self._project.pipeline.disconnect_by_func(self._position_cb)
  44.  
  45.         self._project = project
  46.         if project:
  47.             self._selection = project.ges_timeline.ui.selection
  48.             self._selection.connect('selection-changed', self._selection_changed_cb)
  49.             self._project.pipeline.connect("position", self._position_cb)
  50.  
  51.     def __project_closed_cb(self, unused_project_manager, unused_project):
  52.         self._project = None
  53.  
  54.     def _init_buttons(self):
  55.         spinbtn_start = self.builder.get_object("start_point_spinbtn")
  56.         spinbtn_start.connect("value-changed", self._on_start_changed_cb)
  57.         disable_scroll(spinbtn_start)
  58.         spinbtn_duration = self.builder.get_object("duration_spinbtn")
  59.         spinbtn_duration.connect("value-changed", self._on_duration_changed_cb)
  60.         disable_scroll(spinbtn_duration)
  61.  
  62.     def _init_box_spinners(self):
  63.         self.__setup_box_spinner("duration_measurement")
  64.         self.__setup_box_spinner("start_point_measurement")
  65.  
  66.     def __update_control_bindings(self):
  67.         self.__control_bindings = {}
  68.         if self.__source_uses_keyframes():
  69.             self.__set_control_bindings()
  70.  
  71.     def __source_uses_keyframes(self):
  72.         if self.source is None:
  73.             return False
  74.  
  75.         for prop in ["posy"]:
  76.             binding = self.source.get_control_binding(prop)
  77.             if binding is None:
  78.                 return False
  79.  
  80.         return True
  81.  
  82.     def __remove_control_bindings(self):
  83.         for propname, binding in self.__control_bindings.items():
  84.             control_source = binding.props.control_source
  85.             # control_source.unset_all() can't be used here as it doesn't emit
  86.             # the 'value-removed' signal, so the undo system wouldn't notice
  87.             # the removed keyframes
  88.             keyframes_ts = [keyframe.timestamp for keyframe in control_source.get_all()]
  89.             for ts in keyframes_ts:
  90.                 control_source.unset(ts)
  91.             self.__own_bindings_change = True
  92.             self.source.remove_control_binding(propname)
  93.             self.__own_bindings_change = False
  94.         self.__control_bindings = {}
  95.  
  96.     def __set_control_bindings(self):
  97.         adding_kfs = not self.__source_uses_keyframes()
  98.  
  99.         if adding_kfs:
  100.             self.app.action_log.begin("Transformation properties keyframes activate",
  101.                                       toplevel=True)
  102.  
  103.         for prop in ["posy"]:
  104.             binding = self.source.get_control_binding(prop)
  105.  
  106.             if not binding:
  107.                 control_source = GstController.InterpolationControlSource()
  108.                 control_source.props.mode = GstController.InterpolationMode.LINEAR
  109.                 self.__own_bindings_change = True
  110.                 self.source.set_control_source(control_source, prop, "direct-absolute")
  111.                 self.__own_bindings_change = False
  112.                 self.__set_default_keyframes_values(control_source, prop)
  113.  
  114.                 binding = self.source.get_control_binding(prop)
  115.             self.__control_bindings[prop] = binding
  116.  
  117.         if adding_kfs:
  118.             self.app.action_log.commit("Transformation properties keyframes activate")
  119.  
  120.     def __set_default_keyframes_values(self, control_source, prop):
  121.         res, val = self.source.get_child_property(prop)
  122.         assert res
  123.         control_source.set(self.source.props.in_point, val)
  124.         control_source.set(self.source.props.in_point + self.source.props.duration, val)
  125.  
  126.     def _default_values_cb(self, unused_widget):
  127.         with self.app.action_log.started("Transformation properties reset default",
  128.                                          finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline),
  129.                                          toplevel=True):
  130.             if self.__source_uses_keyframes():
  131.                 self.__remove_control_bindings()
  132.  
  133.             for prop in ["posy"]:
  134.                 self.source.set_child_property(prop, self.source.ui.default_position[prop])
  135.  
  136.     def __get_source_property(self, prop):
  137.         if self.__source_uses_keyframes():
  138.             try:
  139.                 position = self._project.pipeline.get_position()
  140.                 start = self.source.props.start
  141.                 in_point = self.source.props.in_point
  142.                 duration = self.source.props.duration
  143.  
  144.                 # If the position is outside of the clip, take the property
  145.                 # value at the start/end (whichever is closer) of the clip.
  146.                 source_position = max(0, min(position - start, duration - 1)) + in_point
  147.                 value = self.__control_bindings[prop].get_value(source_position)
  148.                 res = value is not None
  149.                 return res, value
  150.             except PipelineError:
  151.                 pass
  152.  
  153.         return self.source.get_child_property(prop)
  154.  
  155.     def _position_cb(self, unused_pipeline, unused_position):
  156.         if not self.__source_uses_keyframes():
  157.             return
  158.         for prop in ["posx", "posy", "width"]:
  159.             self.__update_spin_btn(prop)
  160.         # Keep the overlay stack in sync with the spin buttons values
  161.         self.app.gui.editor.viewer.overlay_stack.update(self.source)
  162.  
  163.     def __source_property_changed_cb(self, unused_source, unused_element, param):
  164.         self.__update_spin_btn(param.name)
  165.  
  166.     def __update_spin_btn(self, prop):
  167.         assert self.source
  168.  
  169.         try:
  170.             spin = self.spin_buttons[prop]
  171.             spin_handler_id = self.spin_buttons_handler_ids[prop]
  172.         except KeyError:
  173.             return
  174.  
  175.         res, value = self.__get_source_property(prop)
  176.         assert res
  177.         if spin.get_value() != value:
  178.             # Make sure self._on_value_changed_cb doesn't get called here. If that
  179.             # happens, we might have unintended keyframes added.
  180.             with spin.handler_block(spin_handler_id):
  181.                 spin.set_value(value)
  182.  
  183.     def _control_bindings_changed(self, unused_track_element, unused_binding):
  184.         if self.__own_bindings_change:
  185.             # Do nothing if the change occurred from this class
  186.             return
  187.  
  188.         self.__update_control_bindings()
  189.  
  190.     def __set_prop(self, prop, value):
  191.         assert self.source
  192.  
  193.         if self.__source_uses_keyframes():
  194.             try:
  195.                 position = self._project.pipeline.get_position()
  196.                 start = self.source.props.start
  197.                 in_point = self.source.props.in_point
  198.                 duration = self.source.props.duration
  199.                 if position < start or position > start + duration:
  200.                     return
  201.                 source_position = position - start + in_point
  202.  
  203.                 with self.app.action_log.started(
  204.                         "Transformation property change",
  205.                         finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline),
  206.                         toplevel=True):
  207.                     self.__control_bindings[prop].props.control_source.set(source_position, value)
  208.             except PipelineError:
  209.                 self.warning("Could not get pipeline position")
  210.                 return
  211.         else:
  212.             with self.app.action_log.started("Transformation property change",
  213.                                              finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline),
  214.                                              toplevel=True):
  215.                 self.source.set_child_property(prop, value)
  216.  
  217.     def __setup_spin_button(self, widget_name, property_name):
  218.         """Creates a SpinButton for editing a property value."""
  219.         spinbtn = self.builder.get_object(widget_name)
  220.         handler_id = spinbtn.connect("value-changed", self._on_value_changed_cb, property_name)
  221.         disable_scroll(spinbtn)
  222.         self.spin_buttons[property_name] = spinbtn
  223.         self.spin_buttons_handler_ids[property_name] = handler_id
  224.  
  225.     def __setup_box_spinner(self, spinner_id):
  226.         seconds_name = spinner_id + "_seconds"
  227.         frames_name = spinner_id + "_frames"
  228.         self.settings[spinner_id] = self.builder.get_object(spinner_id)
  229.         for value_id, text in ((seconds_name, _("Seconds")),
  230.                                (frames_name, _("Frames"))):
  231.             self.settings[spinner_id].append(value_id, text)
  232.  
  233.     def _on_duration_changed_cb(self, spinbtn):
  234.         ges_clip = self._project.ges_timeline.ui.selection.get_single_clip(GES.Clip)
  235.  
  236.         editing_context = EditingContext(ges_clip,
  237.                                          self._project.ges_timeline,
  238.                                          GES.EditMode.EDIT_TRIM,
  239.                                          GES.Edge.EDGE_END,
  240.                                          self.app,
  241.                                          True)
  242.  
  243.         editing_context.edit_to(spinbtn.get_value() * Gst.SECOND + ges_clip.get_start(), ges_clip.ui.layer.ges_layer)
  244.         editing_context.finish()
  245.  
  246.     def _on_start_changed_cb(self, spinbtn):
  247.         ges_clip = self._project.ges_timeline.ui.selection.get_single_clip(GES.Clip)
  248.  
  249.         editing_context = EditingContext(ges_clip,
  250.                                          self._project.ges_timeline,
  251.                                          GES.EditMode.EDIT_NORMAL,
  252.                                          GES.Edge.EDGE_NONE,
  253.                                          self.app,
  254.                                          True)
  255.  
  256.         editing_context.edit_to(spinbtn.get_value() * Gst.SECOND, ges_clip.ui.layer.ges_layer)
  257.         editing_context.finish()
  258.  
  259.     def _on_value_changed_cb(self, spinbtn, prop):
  260.         if not self.source:
  261.             return
  262.  
  263.         value = spinbtn.get_value()
  264.  
  265.         res, cvalue = self.__get_source_property(prop)
  266.         if not res:
  267.             return
  268.  
  269.         if value != cvalue:
  270.             self.__set_prop(prop, value)
  271.             self.app.gui.editor.viewer.overlay_stack.update(self.source)
  272.  
  273.     def __set_source(self, source):
  274.         if self.source:
  275.             try:
  276.                 self.source.disconnect_by_func(self.__source_property_changed_cb)
  277.                 disconnect_all_by_func(self.source, self._control_bindings_changed)
  278.             except TypeError:
  279.                 pass
  280.         self.source = source
  281.         if self.source:
  282.             self.__update_control_bindings()
  283.             for prop in self.spin_buttons:
  284.                 self.__update_spin_btn(prop)
  285.             self.source.connect("deep-notify", self.__source_property_changed_cb)
  286.             self.source.connect("control-binding-added", self._control_bindings_changed)
  287.             self.source.connect("control-binding-removed", self._control_bindings_changed)
  288.  
  289.     def _selection_changed_cb(self, unused_timeline):
  290.         if len(self._selection) == 1:
  291.             clip = list(self._selection)[0]
  292.             source = clip.find_track_element(None, GES.VideoSource)
  293.             if source:
  294.                 self._selected_clip = clip
  295.                 self.__set_source(source)
  296.                 self.app.gui.editor.viewer.overlay_stack.select(source)
  297.                 self.show()
  298.                 return
  299.  
  300.         # Deselect
  301.         if self._selected_clip:
  302.             self._selected_clip = None
  303.             self._project.pipeline.commit_timeline()
  304.         self.__set_source(None)
  305.         self.hide()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top