From 49719e7b12dc56904480b883b22f17a385fc53cc Mon Sep 17 00:00:00 2001 From: UnHired-Coder Date: Mon, 7 Jun 2021 17:37:49 +0530 Subject: [PATCH 001/132] Mini Timeline Layout setup --- pitivi/editorperspective.py | 10 +- pitivi/timeline/elements.py | 330 ++++++++++++++++++-------- pitivi/timeline/layer.py | 179 +++++++++++---- pitivi/timeline/previewers.py | 17 ++ pitivi/timeline/timeline.py | 396 ++++++++++++++++++++++++-------- pitivi/utils/timeline.py | 15 +- pitivi/utils/ui.py | 2 + tests/common.py | 24 +- tests/test_timeline_elements.py | 16 ++ tests/test_timeline_layer.py | 8 +- tests/test_undo_timeline.py | 4 +- 11 files changed, 745 insertions(+), 256 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 8143ed59d..6d64cd92e 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -232,8 +232,16 @@ class EditorPerspective(Perspective, Loggable): self.mainhpaned.pack2(self.viewer, resize=True, shrink=False) # Now, the lower part: the timeline + self.timelinepaned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) + self.timeline_ui = TimelineContainer(self.app, self.editor_state) - self.toplevel_widget.pack2(self.timeline_ui, resize=True, shrink=False) + self.mini_timeline_ui = self.timeline_ui.timeline.mini_layout_container + + self.timelinepaned.pack1(self.mini_timeline_ui, resize=False, shrink=False) + self.timelinepaned.pack2(self.timeline_ui, resize=False, shrink=False) + self.timelinepaned.show_all() + + self.toplevel_widget.pack2(self.timelinepaned, resize=True, shrink=False) self.intro = InteractiveIntro(self.app) self.headerbar.pack_end(self.intro.intro_button) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 6a47c2698..56c072116 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -40,6 +40,7 @@ from pitivi.timeline.markers import ClipMarkersBox from pitivi.timeline.markers import Marker from pitivi.timeline.previewers import AudioPreviewer from pitivi.timeline.previewers import ImagePreviewer +from pitivi.timeline.previewers import MiniPreview from pitivi.timeline.previewers import TitlePreviewer from pitivi.timeline.previewers import VideoPreviewer from pitivi.undo.timeline import CommitTimelineFinalizingAction @@ -1166,13 +1167,12 @@ class TrimHandle(Gtk.EventBox, Loggable): self.props.window.set_cursor(NORMAL_CURSOR) -class Clip(Gtk.EventBox, Zoomable, Loggable): +class Clip(Gtk.EventBox, Loggable): __gtype_name__ = "PitiviClip" def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): Gtk.EventBox.__init__(self) - Zoomable.__init__(self) Loggable.__init__(self) name = ges_clip.get_name() @@ -1188,7 +1188,6 @@ class Clip(Gtk.EventBox, Zoomable, Loggable): self.app = layer.app self.ges_clip = ges_clip - self.ges_clip.ui = self self.ges_clip.selected = Selected() self.ges_clip.selected.selected = self.ges_clip in self.timeline.selection @@ -1196,7 +1195,7 @@ class Clip(Gtk.EventBox, Zoomable, Loggable): self.video_widget = None self._setup_widget() - self.__force_position_update = True + self._force_position_update = True for ges_timeline_element in self.ges_clip.get_children(False): self._add_child(ges_timeline_element) @@ -1221,11 +1220,6 @@ class Clip(Gtk.EventBox, Zoomable, Loggable): self.drag_dest_set(0, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) self.connect("drag-drop", self.__drag_drop_cb) - @property - def layer(self): - ges_layer = self.ges_clip.props.layer - return ges_layer.ui if ges_layer else None - def __drag_drop_cb(self, widget, context, x, y, timestamp): success = False @@ -1276,61 +1270,11 @@ class Clip(Gtk.EventBox, Zoomable, Loggable): return effect return None - def update_position(self): - layer = self.layer - if not layer or layer != self.get_parent(): - # Things are not settled yet. - return - - start = self.ges_clip.props.start - duration = self.ges_clip.props.duration - x = self.ns_to_pixel(start) - # The calculation of the width assumes that the start is always - # int(pixels_float). In that case, the rounding can add up and a pixel - # might be lost if we ignore the start of the clip. - width = self.ns_to_pixel(start + duration) - x - - parent_height = layer.props.height_request - y = 0 - height = parent_height - has_video = self.ges_clip.find_track_elements(None, GES.TrackType.VIDEO, GObject.TYPE_NONE) - has_audio = self.ges_clip.find_track_elements(None, GES.TrackType.AUDIO, GObject.TYPE_NONE) - if not has_video or not has_audio: - if layer.media_types == (GES.TrackType.AUDIO | GES.TrackType.VIDEO): - height = parent_height / 2 - if not has_video: - y = height - - if self.__force_position_update or \ - x != self._current_x or \ - y != self._current_y or \ - width != self._current_width or \ - parent_height != self._current_parent_height or \ - layer != self._current_parent: - - offset_px = self.ns_to_pixel(self.ges_clip.props.in_point) - - for ges_timeline_element in self.ges_clip.get_children(False): - if not ges_timeline_element.ui: - continue - - if ges_timeline_element.ui.markers: - ges_timeline_element.ui.markers.offset = offset_px - - layer.move(self, x, y) - self.set_size_request(width, height) - - elements = self._elements_container.get_children() - for child in elements: - child.set_size(width, height / len(elements)) + def _add_child(self, ges_timeline_element): + """Initializes added Clip's ges_timeline_element.""" - self.__force_position_update = False - # pylint: disable=attribute-defined-outside-init - self._current_x = x - self._current_y = y - self._current_width = width - self._current_parent_height = parent_height - self._current_parent = layer + def update_position(self): + """Updates the UI of the clip.""" def _setup_widget(self): pass @@ -1455,13 +1399,8 @@ class Clip(Gtk.EventBox, Zoomable, Loggable): def __curve_leave_cb(self, unused_keyframe_curve): self.__show_handles() - def _add_child(self, ges_timeline_element: GES.TimelineElement): - ges_timeline_element.selected = Selected() - ges_timeline_element.selected.selected = self.ges_clip.selected.selected - ges_timeline_element.ui = None - def _child_added_cb(self, ges_clip, ges_timeline_element: GES.TimelineElement): - self.__force_position_update = True + self._force_position_update = True self._add_child(ges_timeline_element) self.__connect_to_child(ges_timeline_element) self.update_position() @@ -1470,25 +1409,164 @@ class Clip(Gtk.EventBox, Zoomable, Loggable): pass def _child_removed_cb(self, unused_ges_clip, ges_timeline_element: GES.TimelineElement): - self.__force_position_update = True + self._force_position_update = True self.__disconnect_from_child(ges_timeline_element) self._remove_child(ges_timeline_element) self.update_position() -class SourceClip(Clip): - __gtype_name__ = "PitiviSourceClip" +class FullClip(Clip, Zoomable): + """Full version of Clip(ui).""" def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): + Zoomable.__init__(self) Clip.__init__(self, layer, ges_clip) + self.ges_clip.ui = self + + def _add_child(self, ges_timeline_element): + ges_timeline_element.selected = Selected() + ges_timeline_element.selected.selected = self.ges_clip.selected.selected + ges_timeline_element.ui = None + + def update_position(self): + ges_layer = self.ges_clip.props.layer + layer = ges_layer.ui + if not layer or layer != self.get_parent(): + # Things are not settled yet. + return + + start = self.ges_clip.props.start + duration = self.ges_clip.props.duration + x = self.ns_to_pixel(start) + # The calculation of the width assumes that the start is always + # int(pixels_float). In that case, the rounding can add up and a pixel + # might be lost if we ignore the start of the clip. + width = self.ns_to_pixel(start + duration) - x + + parent_height = layer.props.height_request + y = 0 + height = parent_height + has_video = self.ges_clip.find_track_elements(None, GES.TrackType.VIDEO, GObject.TYPE_NONE) + has_audio = self.ges_clip.find_track_elements(None, GES.TrackType.AUDIO, GObject.TYPE_NONE) + if not has_video or not has_audio: + if layer.media_types == (GES.TrackType.AUDIO | GES.TrackType.VIDEO): + height = parent_height / 2 + if not has_video: + y = height + + if self._force_position_update or \ + x != self._current_x or \ + y != self._current_y or \ + width != self._current_width or \ + parent_height != self._current_parent_height or \ + layer != self._current_parent: + + offset_px = self.ns_to_pixel(self.ges_clip.props.in_point) + + for ges_timeline_element in self.ges_clip.get_children(False): + if not ges_timeline_element.ui: + continue + + if ges_timeline_element.ui.markers: + ges_timeline_element.ui.markers.offset = offset_px + + layer.move(self, x, y) + self.set_size_request(width, height) + + elements = self._elements_container.get_children() + for child in elements: + child.set_size(width, height / len(elements)) + + self._force_position_update = False + # pylint: disable=attribute-defined-outside-init + self._current_x = x + self._current_y = y + self._current_width = width + self._current_parent_height = parent_height + self._current_parent = layer + + +class MiniClip(Clip): + """Mini version of Clip(mini_ui).""" + + __gtype_name__ = "PitiviMiniClip" + + def __init__(self, layer, ges_clip): + Clip.__init__(self, layer, ges_clip) + + self.ges_clip.mini_ui = self + + def _add_child(self, ges_timeline_element): + ges_timeline_element.mini_ui = None + + def update_position(self): + ges_layer = self.ges_clip.props.layer + layer = ges_layer.mini_ui + if not layer or layer != self.get_parent(): + # Things are not settled yet. + return + + start = self.ges_clip.props.start + duration = self.ges_clip.props.duration + ratio = self.timeline.calc_best_zoom_ratio() + x = Zoomable.ns_to_pixel(start, zoomratio=ratio) + # The calculation of the width assumes that the start is always + # int(pixels_float). In that case, the rounding can add up and a pixel + # might be lost if we ignore the start of the clip. + width = Zoomable.ns_to_pixel(start + duration, zoomratio=ratio) - x + + parent_height = layer.props.height_request + y = 0 + + if self._force_position_update or \ + x != self._current_x or \ + y != self._current_y or \ + width != self._current_width or \ + parent_height != self._current_parent_height or \ + layer != self._current_parent: + + layer.move(self, x, y) + self.set_size_request(width, parent_height) + + self._force_position_update = False + # pylint: disable=attribute-defined-outside-init + self._current_x = x + self._current_y = y + self._current_width = width + self._current_parent_height = parent_height + self._current_parent = layer + + +class SourceClip(): + __gtype_name__ = "PitiviSourceClip" + def _setup_widget(self): self._add_trim_handles() self.get_style_context().add_class("Clip") + def _remove_child(self, ges_timeline_element): + if ges_timeline_element.ui: + self._elements_container.remove(ges_timeline_element.ui) + ges_timeline_element.ui = None + + if ges_timeline_element.mini_ui: + self._elements_container.remove(ges_timeline_element.mini_ui) + ges_timeline_element.mini_ui = None + + def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: + raise NotImplementedError() + + +class FullSourceClip(SourceClip, FullClip): + __gtype_name__ = "PitiviFullSourceClip" + + def __init__(self, layer, ges_clip): + FullClip.__init__(self, layer, ges_clip) + def _add_child(self, ges_timeline_element: GES.TimelineElement): - Clip._add_child(self, ges_timeline_element) + FullClip._add_child(self, ges_timeline_element) # In some cases a GESEffect is added here, # so we have to limit the markers initialization to GESSources. @@ -1514,17 +1592,54 @@ class SourceClip(Clip): def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: raise NotImplementedError() - def _remove_child(self, ges_timeline_element): - if ges_timeline_element.ui: - self._elements_container.remove(ges_timeline_element.ui) - ges_timeline_element.ui = None +class MiniSourceClip(SourceClip, MiniClip): + __gtype_name__ = "PitiviMiniSourceClip" + + def __init__(self, layer, ges_clip): + MiniClip.__init__(self, layer, ges_clip) + + def _add_child(self, ges_timeline_element): + MiniClip._add_child(self, ges_timeline_element) + + ges_source: GES.Source = ges_timeline_element + + widget = self._create_child_widget(ges_source) + if not widget: + return + + ges_source.mini_ui = widget + self._elements_container.pack_start(widget, expand=True, fill=False, padding=0) + widget.set_visible(True) + + def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: + raise NotImplementedError() + + +class SimpleClip(MiniSourceClip): + __gtype_name__ = "PitiviSimpleClip" + + def __init__(self, layer, ges_clip): + MiniSourceClip.__init__(self, layer, ges_clip) + self.get_style_context().add_class("SimpleClip") + + def do_query_tooltip(self, x, y, keyboard_mode, tooltip): + tooltip.set_markup(filename_from_uri( + self.ges_clip.get_asset().props.id)) -class UriClip(SourceClip): + return True + + def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: + color, tooltip = GES_TYPE_COLOR_TOOLTIP.get(self.ges_clip.__gtype__, None) + self.props.has_tooltip = tooltip + return MiniPreview(color) + + +class UriClip(FullSourceClip): __gtype_name__ = "PitiviUriClip" def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): - SourceClip.__init__(self, layer, ges_clip) + FullSourceClip.__init__(self, layer, ges_clip) self.get_style_context().add_class("UriClip") self.props.has_tooltip = True @@ -1545,11 +1660,11 @@ class UriClip(SourceClip): return None -class TestClip(SourceClip): +class TestClip(FullSourceClip): __gtype_name__ = "PitiviTestClip" def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): - SourceClip.__init__(self, layer, ges_clip) + FullSourceClip.__init__(self, layer, ges_clip) self.get_style_context().add_class("TestClip") def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: @@ -1560,11 +1675,11 @@ class TestClip(SourceClip): return None -class TitleClip(SourceClip): +class TitleClip(FullSourceClip): __gtype_name__ = "PitiviTitleClip" def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): - SourceClip.__init__(self, layer, ges_clip) + FullSourceClip.__init__(self, layer, ges_clip) self.get_style_context().add_class("TitleClip") def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: @@ -1575,15 +1690,13 @@ class TitleClip(SourceClip): return None -class TransitionClip(Clip): +class TransitionClip(): __gtype_name__ = "PitiviTransitionClip" - def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): + def __init__(self): self.__has_video = False - Clip.__init__(self, layer, ges_clip) - if self.__has_video: self.z_order = 1 else: @@ -1606,8 +1719,6 @@ class TransitionClip(Clip): return True def _add_child(self, ges_timeline_element): - Clip._add_child(self, ges_timeline_element) - if not isinstance(ges_timeline_element, GES.VideoTransition): return @@ -1623,9 +1734,48 @@ class TransitionClip(Clip): self.app.gui.editor.trans_list.deactivate() +class FullTransitionClip(TransitionClip, FullClip): + + __gtype_name__ = "PitiviFullTransitionClip" + + def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): + FullClip.__init__(self, layer, ges_clip) + TransitionClip.__init__(self) + + def _add_child(self, ges_timeline_element): + FullClip._add_child(self, ges_timeline_element) + TransitionClip._add_child(self, ges_timeline_element) + + +class MiniTransitionClip(TransitionClip, MiniClip): + + __gtype_name__ = "PitiviMiniTransitionClip" + + def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): + MiniClip.__init__(self, layer, ges_clip) + TransitionClip.__init__(self) + + def _add_child(self, ges_timeline_element): + MiniClip._add_child(self, ges_timeline_element) + TransitionClip._add_child(self, ges_timeline_element) + + GES_TYPE_UI_TYPE = { GES.UriClip.__gtype__: UriClip, GES.TitleClip.__gtype__: TitleClip, - GES.TransitionClip.__gtype__: TransitionClip, + GES.TransitionClip.__gtype__: FullTransitionClip, GES.TestClip.__gtype__: TestClip } + +GES_TYPE_COLOR_TOOLTIP = { + GES.UriClip.__gtype__: ((0.214, 0.50, 0.39), True), + GES.TitleClip.__gtype__: ((0.819, 0.20, 0.267), False), + GES.TestClip.__gtype__: ((0.619, 0.670, 0.067), False) +} + +GES_TYPE_MINI_UI_TYPE = { + GES.UriClip.__gtype__: SimpleClip, + GES.TitleClip.__gtype__: SimpleClip, + GES.TransitionClip.__gtype__: MiniTransitionClip, + GES.TestClip.__gtype__: SimpleClip +} diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 2b80a78c6..80f5e32ec 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -27,6 +27,7 @@ from pitivi.undo.timeline import CommitTimelineFinalizingAction from pitivi.utils.loggable import Loggable from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import LAYER_HEIGHT +from pitivi.utils.ui import MINI_LAYER_HEIGHT from pitivi.utils.ui import PADDING from pitivi.utils.ui import SEPARATOR_HEIGHT @@ -292,18 +293,16 @@ class LayerControls(Gtk.EventBox, Loggable): self.__icon = icon -class Layer(Gtk.Layout, Zoomable, Loggable): +class Layer(Gtk.Layout, Loggable): """Container for the clips widgets of a layer.""" __gtype_name__ = "PitiviLayer" def __init__(self, ges_layer, timeline): Gtk.Layout.__init__(self) - Zoomable.__init__(self) Loggable.__init__(self) self.ges_layer = ges_layer - self.ges_layer.ui = self self.timeline = timeline self.app = timeline.app @@ -318,9 +317,7 @@ class Layer(Gtk.Layout, Zoomable, Loggable): self.props.valign = Gtk.Align.START self.media_types = GES.TrackType(0) - for ges_clip in ges_layer.get_clips(): - self._add_clip(ges_clip) - self.check_media_types() + self.old_media_types = GES.TrackType(0) def set_name(self, name): self.ges_layer.set_meta("video::name", name) @@ -351,12 +348,13 @@ class Layer(Gtk.Layout, Zoomable, Loggable): self.ges_layer.disconnect_by_func(self._clip_added_cb) self.ges_layer.disconnect_by_func(self._clip_removed_cb) - def check_media_types(self): + def _check_media_types(self): if self.timeline.editing_context: - self.info("Not updating media types as we are editing the timeline") + self.info("Not updating media types as" + " we are editing the timeline") return - old_media_types = self.media_types + self.old_media_types = self.media_types self.media_types: GES.TrackType = GES.TrackType(0) ges_clips = self.ges_layer.get_clips() for ges_clip in ges_clips: @@ -365,18 +363,6 @@ class Layer(Gtk.Layout, Zoomable, Loggable): # Cannot find more types than these. break - if self.media_types & GES.TrackType.AUDIO and self.media_types & GES.TrackType.VIDEO: - self.props.height_request = LAYER_HEIGHT - else: - # If the layer is empty, set layer's height to default height. - self.props.height_request = LAYER_HEIGHT // 2 - - if hasattr(self.ges_layer, "control_ui") and self.ges_layer.control_ui: - self.ges_layer.control_ui.update(self.media_types) - - if old_media_types != self.media_types: - self.update_position() - def _clip_child_added_cb(self, ges_clip, child): self.check_media_types() @@ -387,19 +373,13 @@ class Layer(Gtk.Layout, Zoomable, Loggable): self._add_clip(ges_clip) self.check_media_types() - def _add_clip(self, ges_clip): - ui_type = elements.GES_TYPE_UI_TYPE.get(ges_clip.__gtype__, None) - if ui_type is None: - self.error("Implement UI for type %s?", ges_clip.__gtype__) - return - - widget = ui_type(self, ges_clip) - self._children.append(widget) + def _add_clip_ui(self, ges_clip, clip_ui): + self._children.append(clip_ui) self._children.sort(key=lambda clip: clip.z_order) - self.put(widget, self.ns_to_pixel(ges_clip.props.start), 0) - widget.update_position() + + clip_ui.update_position() self._changed = True - widget.show_all() + clip_ui.show_all() ges_clip.connect_after("child-added", self._clip_child_added_cb) ges_clip.connect_after("child-removed", self._clip_child_removed_cb) @@ -408,28 +388,18 @@ class Layer(Gtk.Layout, Zoomable, Loggable): self._remove_clip(ges_clip) self.check_media_types() - def _remove_clip(self, ges_clip): - if not ges_clip.ui: - return - - ui_type = elements.GES_TYPE_UI_TYPE.get(ges_clip.__gtype__, None) - if ui_type is None: - self.error("Implement UI for type %s?", ges_clip.__gtype__) - return - - self.remove(ges_clip.ui) - self._children.remove(ges_clip.ui) + def _remove_clip_ui(self, ges_clip, clip_ui): + self.remove(clip_ui) + self._children.remove(clip_ui) self._changed = True - ges_clip.ui.release() - ges_clip.ui = None + clip_ui.release() + clip_ui = None ges_clip.disconnect_by_func(self._clip_child_added_cb) ges_clip.disconnect_by_func(self._clip_child_removed_cb) def update_position(self): - for ges_clip in self.ges_layer.get_clips(): - if hasattr(ges_clip, "ui"): - ges_clip.ui.update_position() + pass def do_draw(self, cr): if self._changed: @@ -442,3 +412,116 @@ class Layer(Gtk.Layout, Zoomable, Loggable): for child in self._children: self.propagate_draw(child, cr) + + +class FullLayer(Layer, Zoomable): + """Container for the Full clips.""" + + __gtype_name__ = "PitiviFullLayer" + + def __init__(self, ges_layer, timeline): + Layer.__init__(self, ges_layer, timeline) + Zoomable.__init__(self) + + self.ges_layer.ui = self + for ges_clip in ges_layer.get_clips(): + self._add_clip(ges_clip) + self.check_media_types() + + def check_media_types(self): + Layer._check_media_types(self) + + if self.media_types & GES.TrackType.AUDIO and self.media_types & GES.TrackType.VIDEO: + self.props.height_request = LAYER_HEIGHT + else: + # If the layer is empty, set layer's height to default height. + self.props.height_request = LAYER_HEIGHT // 2 + + if hasattr(self.ges_layer, "control_ui") and self.ges_layer.control_ui: + self.ges_layer.control_ui.update(self.media_types) + + if self.old_media_types != self.media_types: + self.update_position() + + def _add_clip(self, ges_clip): + ui_type = elements.GES_TYPE_UI_TYPE.get(ges_clip.__gtype__, None) + if ui_type is None: + self.error("Implement UI for type %s?", ges_clip.__gtype__) + return + + widget = ui_type(self, ges_clip) + self.put(widget, self.ns_to_pixel(ges_clip.props.start), 0) + Layer._add_clip_ui(self, ges_clip, widget) + + def _remove_clip(self, ges_clip): + if not ges_clip.ui: + return + + ui_type = elements.GES_TYPE_UI_TYPE.get(ges_clip.__gtype__, None) + if ui_type is None: + self.error("Implement UI for type %s?", ges_clip.__gtype__) + return + + Layer._remove_clip_ui(self, ges_clip, ges_clip.ui) + + def update_position(self): + for ges_clip in self.ges_layer.get_clips(): + if hasattr(ges_clip, 'ui') and ges_clip.ui: + ges_clip.ui.update_position() + + +class MiniLayer(Layer): + """Container for the Mini clips.""" + + __gtype_name__ = "PitiviMiniLayer" + + def __init__(self, ges_layer, timeline): + Layer.__init__(self, ges_layer, timeline) + + self.ges_layer.mini_ui = self + for ges_clip in ges_layer.get_clips(): + self._add_clip(ges_clip) + self.check_media_types() + + def check_media_types(self): + if self.timeline.editing_context: + self.info("Not updating media types as" + " we are editing the timeline") + return + + self.props.height_request = MINI_LAYER_HEIGHT + + def _add_clip(self, ges_clip): + ui_type = elements.GES_TYPE_MINI_UI_TYPE.get(ges_clip.__gtype__, None) + if ui_type is None: + self.error("Implement Mini UI for type %s?", ges_clip.__gtype__) + return + + widget = ui_type(self, ges_clip) + ratio = self.timeline.calc_best_zoom_ratio() + x = Zoomable.ns_to_pixel(ges_clip.props.start, zoomratio=ratio) + self.put(widget, x, 0) + Layer._add_clip_ui(self, ges_clip, widget) + + def _remove_clip(self, ges_clip): + if not ges_clip.mini_ui: + return + + ui_type = elements.GES_TYPE_MINI_UI_TYPE.get(ges_clip.__gtype__, None) + if ui_type is None: + self.error("Implement Mini UI for type %s?", ges_clip.__gtype__) + return + + Layer._remove_clip_ui(self, ges_clip, ges_clip.mini_ui) + + def update_position(self): + pass + + def do_draw(self, context): + Layer.do_draw(self, context) + + for layer in self.timeline.ges_timeline.get_layers(): + # pylint: disable=W0212 + for child in layer.mini_ui._children: + child.update_position() + self.timeline.mini_layout.queue_draw() diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py index 12224f4ef..d299857b9 100644 --- a/pitivi/timeline/previewers.py +++ b/pitivi/timeline/previewers.py @@ -47,6 +47,7 @@ from pitivi.utils.system import CPUUsageTracker from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import CLIP_BORDER_WIDTH from pitivi.utils.ui import EXPANDED_SIZE +from pitivi.utils.ui import MINI_LAYER_HEIGHT # Our C module optimizing waveforms rendering try: @@ -1488,3 +1489,19 @@ class TitlePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): def release(self): # Nothing to release pass + + +class MiniPreview(Gtk.Layout): + """Mini Clip previewer to draw color filled mini clips.""" + + def __init__(self, color): + Gtk.Layout.__init__(self) + self.get_style_context().add_class("MiniPreviewer") + self.color = color + self.props.height_request = MINI_LAYER_HEIGHT + + def do_draw(self, context): + rect = Gdk.cairo_get_clip_rectangle(context)[1] + context.set_source_rgb(*self.color) + context.rectangle(0, 0, rect.width, rect.height) + context.fill() diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 8b341d67e..f19e3de53 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -37,8 +37,9 @@ from pitivi.settings import GlobalSettings from pitivi.timeline.elements import Clip from pitivi.timeline.elements import TransitionClip from pitivi.timeline.elements import TrimHandle -from pitivi.timeline.layer import Layer +from pitivi.timeline.layer import FullLayer from pitivi.timeline.layer import LayerControls +from pitivi.timeline.layer import MiniLayer from pitivi.timeline.layer import SpacedSeparator from pitivi.timeline.markers import MarkersBox from pitivi.timeline.previewers import Previewer @@ -56,6 +57,7 @@ from pitivi.utils.timeline import UNSELECT from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import EFFECT_TARGET_ENTRY from pitivi.utils.ui import LAYER_HEIGHT +from pitivi.utils.ui import MINI_LAYER_HEIGHT from pitivi.utils.ui import PLAYHEAD_COLOR from pitivi.utils.ui import PLAYHEAD_WIDTH from pitivi.utils.ui import SEPARATOR_HEIGHT @@ -135,15 +137,17 @@ class Marquee(Gtk.Box, Loggable): Args: timeline (Timeline): The timeline indirectly containing the marquee. + layout (LayersLayout): Layout containing the layers on which the marquee would be drawn. """ __gtype_name__ = "PitiviMarquee" - def __init__(self, timeline): + def __init__(self, timeline, layout): Gtk.Box.__init__(self) Loggable.__init__(self) self._timeline = timeline + self.layout = layout self.start_x, self.start_y = 0, 0 self.end_x, self.end_y = self.start_x, self.start_y @@ -168,7 +172,7 @@ class Marquee(Gtk.Box, Loggable): """ event_widget = Gtk.get_event_widget(event) self.start_x, self.start_y = event_widget.translate_coordinates( - self._timeline.layout.layers_vbox, event.x, event.y) + self.layout.layers_vbox, event.x, event.y) self.end_x, self.end_y = self.start_x, self.start_y self.get_parent().move(self, self.start_x, self.start_y) @@ -185,7 +189,7 @@ class Marquee(Gtk.Box, Loggable): """ event_widget = Gtk.get_event_widget(event) self.end_x, self.end_y = event_widget.translate_coordinates( - self._timeline.layout.layers_vbox, event.x, event.y) + self.layout.layers_vbox, event.x, event.y) x = min(self.start_x, self.end_x) y = min(self.start_y, self.end_y) @@ -194,25 +198,30 @@ class Marquee(Gtk.Box, Loggable): self.props.width_request = abs(self.start_x - self.end_x) self.props.height_request = abs(self.start_y - self.end_y) - def find_clips(self): + def find_clips(self, mini=False): """Finds the clips which intersect the marquee. + Args: + mini (bool): Layers layout or Mini Layers layout. + Returns: List[GES.Clip]: The clips under the marquee. """ if self.props.width_request == 0: return [] - start_layer = self._timeline.get_layer_at(self.start_y)[0] - end_layer = self._timeline.get_layer_at(self.end_y)[0] - start_pos = max(0, self._timeline.pixel_to_ns(self.start_x)) - end_pos = max(0, self._timeline.pixel_to_ns(self.end_x)) + start_layer = self._timeline.get_layer_at(self.start_y, mini=mini)[0] + end_layer = self._timeline.get_layer_at(self.end_y, mini=mini)[0] + + ratio = self._timeline.calc_best_zoom_ratio() if mini else None + start_pos = max(0, self._timeline.pixel_to_ns(self.start_x, zoomratio=ratio)) + end_pos = max(0, self._timeline.pixel_to_ns(self.end_x, zoomratio=ratio)) return self._timeline.get_clips_in_between(start_layer, end_layer, start_pos, end_pos) -class LayersLayout(Gtk.Layout, Zoomable, Loggable): +class LayersLayout(Gtk.Layout, Loggable): """Layout for displaying scrollable layers, the playhead, snap indicator. The layers are actual widgets in a vertical Gtk.Box. @@ -228,7 +237,6 @@ class LayersLayout(Gtk.Layout, Zoomable, Loggable): def __init__(self, timeline): Gtk.Layout.__init__(self) - Zoomable.__init__(self) Loggable.__init__(self) self._timeline = timeline @@ -240,41 +248,31 @@ class LayersLayout(Gtk.Layout, Zoomable, Loggable): self.layers_vbox.get_style_context().add_class("LayersBox") self.put(self.layers_vbox, 0, 0) - self.marquee = Marquee(timeline) + self.marquee = Marquee(timeline, self) self.put(self.marquee, 0, 0) self.layers_vbox.connect("size-allocate", self.__size_allocate_cb) - def zoom_changed(self): - # The width of the area/workspace changes when the zoom level changes. - self.update_width() - # Required so the playhead is redrawn. - self.queue_draw() - def do_draw(self, cr): """Draws the children and indicators.""" Gtk.Layout.do_draw(self, cr) - self.__draw_playhead(cr) - self.__draw_snap_indicator(cr) - - def __draw_playhead(self, cr): - """Draws the playhead line.""" - offset = self.get_hadjustment().get_value() - position = max(0, self.playhead_position) - x = self.ns_to_pixel(position) - offset - self.__draw_vertical_bar(cr, x, PLAYHEAD_WIDTH, PLAYHEAD_COLOR) + self._draw_playhead(cr) + self._draw_snap_indicator(cr) - def __draw_snap_indicator(self, cr): - """Draws a snapping indicator line.""" - offset = self.get_hadjustment().get_value() - x = self.ns_to_pixel(self.snap_position) - offset - if x <= 0: - return + def update_width(self, width): + """Updates the width of the area and the width of the layers_vbox.""" + view_width = self.get_allocated_width() + space_at_the_end = view_width * 2 / 3 + width = width + space_at_the_end + width = max(view_width, width) - self.__draw_vertical_bar(cr, x, SNAPBAR_WIDTH, SNAPBAR_COLOR) + self.log("Updating the width_request of the layers_vbox: %s", width) + # This triggers a renegotiation of the size, meaning + # layers_vbox's "size-allocate" will be emitted, see __size_allocate_cb. + self.layers_vbox.props.width_request = width - def __draw_vertical_bar(self, cr, xpos, width, color): + def _draw_vertical_bar(self, cr, xpos, width, color): if xpos < 0: return @@ -287,20 +285,6 @@ class LayersLayout(Gtk.Layout, Zoomable, Loggable): cr.line_to(xpos, height) cr.stroke() - def update_width(self): - """Updates the width of the area and the width of the layers_vbox.""" - ges_timeline = self._timeline.ges_timeline - view_width = self.get_allocated_width() - space_at_the_end = view_width * 2 / 3 - duration = 0 if not ges_timeline else ges_timeline.props.duration - width = self.ns_to_pixel(duration) + space_at_the_end - width = max(view_width, width) - - self.log("Updating the width_request of the layers_vbox: %s", width) - # This triggers a renegotiation of the size, meaning - # layers_vbox's "size-allocate" will be emitted, see __size_allocate_cb. - self.layers_vbox.props.width_request = width - def __size_allocate_cb(self, unused_widget, allocation): """Sets the size of the scrollable area to fit the layers_vbox.""" self.log("The size of the layers_vbox changed: %sx%s", allocation.width, allocation.height) @@ -309,6 +293,76 @@ class LayersLayout(Gtk.Layout, Zoomable, Loggable): self.props.height = allocation.height + LAYER_HEIGHT / 2 +class FullLayersLayout(LayersLayout, Zoomable): + + def __init__(self, timeline): + Zoomable.__init__(self) + LayersLayout.__init__(self, timeline) + + def _draw_playhead(self, cr): + """Draws the playhead line.""" + offset = self.get_hadjustment().get_value() + position = max(0, self.playhead_position) + + x = self.ns_to_pixel(position) - offset + self._draw_vertical_bar(cr, x, PLAYHEAD_WIDTH, PLAYHEAD_COLOR) + + def _draw_snap_indicator(self, cr): + """Draws a snapping indicator line.""" + offset = self.get_hadjustment().get_value() + x = self.ns_to_pixel(self.snap_position) - offset + if x <= 0: + return + + self._draw_vertical_bar(cr, x, SNAPBAR_WIDTH, SNAPBAR_COLOR) + + def update_width(self): + ges_timeline = self._timeline.ges_timeline + duration = 0 if not ges_timeline else ges_timeline.props.duration + width = self.ns_to_pixel(duration) + + LayersLayout.update_width(self, width) + + def zoom_changed(self): + # The width of the area/workspace changes when the zoom level changes. + self.update_width() + # Required so the playhead is redrawn. + self.queue_draw() + + +class MiniLayersLayout(LayersLayout): + + def __init__(self, timeline): + LayersLayout.__init__(self, timeline) + + def _draw_playhead(self, cr): + """Draws the playhead line.""" + offset = self.get_hadjustment().get_value() + position = max(0, self.playhead_position) + + ratio = self._timeline.calc_best_zoom_ratio() + x = Zoomable.ns_to_pixel(position, zoomratio=ratio) - offset + self._draw_vertical_bar(cr, x, PLAYHEAD_WIDTH, PLAYHEAD_COLOR) + + def _draw_snap_indicator(self, cr): + """Draws a snapping indicator line.""" + offset = self.get_hadjustment().get_value() + ratio = self._timeline.calc_best_zoom_ratio() + x = Zoomable.ns_to_pixel(self.snap_position, zoomratio=ratio) - offset + if x <= 0: + return + + self._draw_vertical_bar(cr, x, SNAPBAR_WIDTH, SNAPBAR_COLOR) + + def update_width(self): + ges_timeline = self._timeline.ges_timeline + duration = 0 if not ges_timeline else ges_timeline.props.duration + ratio = self._timeline.calc_best_zoom_ratio() + width = Zoomable.ns_to_pixel(duration, zoomratio=ratio) + + LayersLayout.update_width(self, width) + + class Timeline(Gtk.EventBox, Zoomable, Loggable): """Container for the layers controls and representation. @@ -333,13 +387,22 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.add(hbox) - self.layout = LayersLayout(self) + self.layout = FullLayersLayout(self) self.layout.props.can_focus = True self.layout.props.can_default = True self.hadj = self.layout.get_hadjustment() self.vadj = self.layout.get_vadjustment() hbox.pack_end(self.layout, True, True, 0) + self.mini_layout = MiniLayersLayout(self) + + self.mini_layout_container = Gtk.EventBox.new() + self.mini_layout_container.add(self.mini_layout) + self.mini_layout_container.add_events(Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE) + self.mini_layout_container.props.no_show_all = True + self.mini_layout_container.props.height_request = MINI_LAYER_HEIGHT + self.mini_layout_container.hide() + self._layers_controls_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self._layers_controls_vbox.props.hexpand = False self._layers_controls_vbox.props.valign = Gtk.Align.START @@ -390,6 +453,10 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.delayed_scroll = {} self.__next_seek_position = None + # Whether the playhead is in Locked mode + # If this is true, Playhead will center itself. + self.playhead_locked = False + # Clip selection. self.selection = Selection() # The last layer where the user clicked. @@ -434,14 +501,22 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): # To be able to receive effects dragged on clips. self.drag_dest_set(0, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) + self.mini_layout_container.drag_dest_set(0, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) # To be able to receive assets dragged from the media library. self.drag_dest_add_uri_targets() + self.mini_layout_container.drag_dest_add_uri_targets() self.connect("drag-motion", self._drag_motion_cb) self.connect("drag-leave", self._drag_leave_cb) self.connect("drag-drop", self._drag_drop_cb) self.connect("drag-data-received", self._drag_data_received_cb) + mini = True + self.mini_layout_container.connect("drag-motion", self._drag_motion_cb, mini) + self.mini_layout_container.connect("drag-leave", self._drag_leave_cb) + self.mini_layout_container.connect("drag-drop", self._drag_drop_cb) + self.mini_layout_container.connect("drag-data-received", self._drag_data_received_cb) + self.app.settings.connect("edgeSnapDeadbandChanged", self.__snap_distance_changed_cb) @@ -479,6 +554,10 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.disconnect_by_func(self._button_release_event_cb) self.disconnect_by_func(self._motion_notify_event_cb) + self.mini_layout_container.disconnect_by_func(self._button_press_event_cb) + self.mini_layout_container.disconnect_by_func(self._button_release_event_cb) + self.mini_layout_container.disconnect_by_func(self._motion_notify_event_cb) + self.ges_timeline.disconnect_by_func(self._duration_changed_cb) self.ges_timeline.disconnect_by_func(self._layer_added_cb) self.ges_timeline.disconnect_by_func(self._layer_removed_cb) @@ -506,6 +585,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): for ges_layer in self.ges_timeline.get_layers(): self._add_layer(ges_layer) self.__update_layers() + self.__update_mini_timeline_height() self.ges_timeline.connect("notify::duration", self._duration_changed_cb) self.ges_timeline.connect("layer-added", self._layer_added_cb) @@ -517,10 +597,17 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.connect("button-release-event", self._button_release_event_cb) self.connect("motion-notify-event", self._motion_notify_event_cb) + mini = True + self.mini_layout_container.connect("button-press-event", self._button_press_event_cb, mini) + self.mini_layout_container.connect("button-release-event", self._button_release_event_cb, mini) + self.mini_layout_container.connect("motion-notify-event", self._motion_notify_event_cb, mini) + self.layout.update_width() + self.mini_layout.update_width() def _duration_changed_cb(self, ges_timeline, pspec): self.layout.update_width() + self.mini_layout.update_width() def scroll_to_playhead(self, align=None, when_not_in_view=False, delayed=False): """Scrolls so that the playhead is in view. @@ -564,9 +651,15 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.__last_position = position self.layout.playhead_position = position self.layout.queue_draw() + + self.mini_layout.playhead_position = position + self.mini_layout.queue_draw() + layout_width = self.layout.get_allocation().width x = self.ns_to_pixel(self.__last_position) - self.hadj.get_value() - if pipeline.playing() and x > layout_width - 100: + if self.playhead_locked: + self.scroll_to_playhead() + elif pipeline.playing() and x > layout_width - 100: self.scroll_to_playhead(Gtk.Align.START) if not pipeline.playing(): self.update_visible_overlays() @@ -577,6 +670,9 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.layout.snap_position = position self.layout.queue_draw() + self.mini_layout.snap_position = position + self.mini_layout.queue_draw() + def __snapping_ended_cb(self, *unused_args): self.__end_snap() @@ -585,6 +681,9 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.layout.snap_position = 0 self.layout.queue_draw() + self.mini_layout.snap_position = 0 + self.mini_layout.queue_draw() + def update_snapping_distance(self): """Updates the snapping distance of self.ges_timeline.""" self.ges_timeline.set_snapping_distance( @@ -726,7 +825,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): """ self.__next_seek_position = next_seek_position - def _button_press_event_cb(self, unused_widget, event): + def _button_press_event_cb(self, unused_widget, event, mini=False): """Handles a mouse button press event.""" self.debug("PRESSED %s", event) self.app.gui.editor.focus_timeline() @@ -742,7 +841,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): if self.dragging_element: self.__drag_start_x = event.x - self._on_layer = self.dragging_element.layer.ges_layer + self._on_layer = self.dragging_element.ges_clip.props.layer else: layer_controls = self._get_parent_of_type(event_widget, LayerControls) if layer_controls: @@ -751,11 +850,14 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline), toplevel=True) else: - self.layout.marquee.set_start_position(event) + if not mini: + self.layout.marquee.set_start_position(event) + else: + self.mini_layout.marquee.set_start_position(event) self.scrubbing = res and button == 3 if self.scrubbing: - self._seek(event) + self._seek(event, mini) clip = self._get_parent_of_type(event_widget, Clip) if clip: clip.shrink_trim_handles() @@ -766,7 +868,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self._scroll_start_x = event.x self._scroll_start_y = event.y - def _button_release_event_cb(self, unused_widget, event): + def _button_release_event_cb(self, unused_widget, event, mini=False): self.debug("RELEASED %s", event) allow_seek = not self.__got_dragged @@ -777,9 +879,14 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.__end_moving_layer() return False elif self.layout.marquee.is_visible() and res and button == 1: - clips = self.layout.marquee.find_clips() - self.selection.set_selection(clips, SELECT) - self.layout.marquee.hide() + if not mini: + clips = self.layout.marquee.find_clips(mini=mini) + self.selection.set_selection(clips, SELECT) + self.layout.marquee.hide() + else: + clips = self.mini_layout.marquee.find_clips(mini=mini) + self.selection.set_selection(clips, SELECT) + self.mini_layout.marquee.hide() self.scrubbing = False @@ -793,22 +900,22 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): else: event_widget = Gtk.get_event_widget(event) if event_widget and self._get_parent_of_type(event_widget, LayerControls) is None: - self._seek(event) + self._seek(event, mini) # Allowing group clips selection by shift+clicking anywhere on the timeline. if self.get_parent().shift_mask: last_clicked_layer = self.last_clicked_layer if not last_clicked_layer: - clicked_layer, click_pos = self.get_clicked_layer_and_pos(event) + clicked_layer, click_pos = self.get_clicked_layer_and_pos(event, mini=mini) self.set_selection_meta_info(clicked_layer, click_pos, SELECT) else: last_click_pos = self.last_click_pos - cur_clicked_layer, cur_click_pos = self.get_clicked_layer_and_pos(event) + cur_clicked_layer, cur_click_pos = self.get_clicked_layer_and_pos(event, mini=mini) clips = self.get_clips_in_between( last_clicked_layer, cur_clicked_layer, last_click_pos, cur_click_pos) self.selection.set_selection(clips, SELECT) elif not self.get_parent().control_mask: - clicked_layer, click_pos = self.get_clicked_layer_and_pos(event) + clicked_layer, click_pos = self.get_clicked_layer_and_pos(event, mini=mini) self.set_selection_meta_info(clicked_layer, click_pos, SELECT) self.__end_snap() @@ -824,12 +931,14 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.last_clicked_layer = clicked_layer self.last_click_pos = click_pos - def get_clicked_layer_and_pos(self, event): + def get_clicked_layer_and_pos(self, event, mini=False): """Gets layer and position in the timeline where user clicked.""" event_widget = Gtk.get_event_widget(event) - x, y = event_widget.translate_coordinates(self.layout.layers_vbox, event.x, event.y) - clicked_layer = self.get_layer_at(y)[0] - click_pos = max(0, self.pixel_to_ns(x)) + layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox + x, y = event_widget.translate_coordinates(layers_box, event.x, event.y) + clicked_layer = self.get_layer_at(y, mini=mini)[0] + ratio = self.calc_best_zoom_ratio() if mini else None + click_pos = max(0, self.pixel_to_ns(x, zoomratio=ratio)) return clicked_layer, click_pos def get_clips_in_between(self, layer1, layer2, pos1, pos2): @@ -867,7 +976,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): for clip in layer.get_clips(): yield clip - def _motion_notify_event_cb(self, unused_widget, event): + def _motion_notify_event_cb(self, unused_widget, event, mini=False): if self.dragging_element: if self.dragging_group is None: self.dragging_group = self.selection.group() @@ -885,22 +994,25 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): if self.got_dragged or self.__past_threshold(event): event_widget = Gtk.get_event_widget(event) - x, y = event_widget.translate_coordinates(self.layout.layers_vbox, event.x, event.y) - self.__drag_update(x, y) + layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox + x, y = event_widget.translate_coordinates(layers_box, event.x, event.y) + self.__drag_update(x, y, mini) self.got_dragged = True elif self.__moving_layer: event_widget = Gtk.get_event_widget(event) unused_x, y = event_widget.translate_coordinates(self, event.x, event.y) layer, unused_on_sep = self.get_layer_at( y, prefer_ges_layer=self.__moving_layer, - past_middle_when_adjacent=True) + past_middle_when_adjacent=True, mini=mini) if layer != self.__moving_layer: priority = layer.get_priority() self.move_layer(self.__moving_layer, priority) elif self.layout.marquee.is_visible(): self.layout.marquee.move(event) + elif self.mini_layout.marquee.is_visible(): + self.mini_layout.marquee.move(event) elif self.scrubbing: - self._seek(event) + self._seek(event, mini) elif self._scrolling: self.__scroll(event) @@ -922,10 +1034,13 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): return delta_x > threshold - def _seek(self, event): + def _seek(self, event, mini=False): event_widget = Gtk.get_event_widget(event) - x, unused_y = event_widget.translate_coordinates(self.layout.layers_vbox, event.x, event.y) - position = max(0, self.pixel_to_ns(x)) + layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox + x, unused_y = event_widget.translate_coordinates(layers_box, event.x, event.y) + + ratio = self.calc_best_zoom_ratio() if mini else None + position = max(0, self.pixel_to_ns(x, zoomratio=ratio)) self._project.pipeline.simple_seek(position) def __scroll(self, event): @@ -971,12 +1086,13 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): duration_frames = self.ges_timeline.get_frame_at(duration) return self.ges_timeline.get_frame_time(duration_frames) - def __create_clips(self, x, y): + def __create_clips(self, x, y, mini=False): """Creates the clips for an asset drag operation. Args: x (int): The x coordinate relative to the layers box. y (int): The y coordinate relative to the layers box. + mini (bool): Event from Mini Timeline or Simple Timeline """ placement = 0 self.dragging_element = None @@ -989,9 +1105,10 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): ges_clips = [] self.app.action_log.begin("Add clips") for asset in assets: - ges_layer, unused_on_sep = self.get_layer_at(y) + ges_layer, unused_on_sep = self.get_layer_at(y, mini=mini) if not placement: - placement = max(0, self.pixel_to_ns(x)) + ratio = self.calc_best_zoom_ratio() if mini else None + placement = max(0, self.pixel_to_ns(x, zoomratio=ratio)) self.debug("Adding %s at %s on layer %s", asset.props.id, Gst.TIME_ARGS(placement), ges_layer) self.app.action_log.begin("Add one clip") @@ -1019,7 +1136,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): if ges_clips: ges_clip = ges_clips[0] - self.dragging_element = ges_clip.ui + self.dragging_element = ges_clip.ui if not mini else ges_clip.mini_ui self._on_layer = ges_layer self.dropping_clips = True @@ -1027,7 +1144,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.dragging_group = self.selection.group() - def _drag_motion_cb(self, widget, context, x, y, timestamp): + def _drag_motion_cb(self, widget, context, x, y, timestamp, mini=False): target = self.drag_dest_find_target(context, None) if not target: Gdk.drag_status(context, 0, timestamp) @@ -1038,11 +1155,12 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): # Ask for the details. self.drag_get_data(context, target, timestamp) elif target.name() == URI_TARGET_ENTRY.target: - x, y = widget.translate_coordinates(self.layout.layers_vbox, x, y) + layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox + x, y = widget.translate_coordinates(layers_box, x, y) if not self.dropping_clips: # The preview clips have not been created yet. - self.__create_clips(x, y) - self.__drag_update(x, y) + self.__create_clips(x, y, mini) + self.__drag_update(x, y, mini) Gdk.drag_status(context, Gdk.DragAction.COPY, timestamp) return True @@ -1129,6 +1247,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): def _layer_added_cb(self, unused_ges_timeline, ges_layer): self._add_layer(ges_layer) self.__update_layers() + self.__update_mini_timeline_height() def move_layer(self, ges_layer, index): self.debug("Moving layer %s to %s", ges_layer.props.priority, index) @@ -1141,9 +1260,12 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): def _add_layer(self, ges_layer): """Adds widgets for controlling and showing the specified layer.""" - layer = Layer(ges_layer, self) + layer = FullLayer(ges_layer, self) ges_layer.ui = layer + mini_layer = MiniLayer(ges_layer, self) + ges_layer.mini_ui = mini_layer + if not self._separators: # Make sure the first layer has separators above it. self.__add_separators() @@ -1154,10 +1276,14 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): ges_layer.control_ui = control # Check the media types so the controls are set up properly. layer.check_media_types() + mini_layer.check_media_types() self.layout.layers_vbox.pack_start(layer, False, False, 0) layer.show() + self.mini_layout.layers_vbox.pack_start(mini_layer, False, False, 0) + mini_layer.show() + self.__add_separators() ges_layer.connect("notify::priority", self.__layer_priority_changed_cb) @@ -1172,7 +1298,11 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): separator.show() self.layout.layers_vbox.pack_start(separator, False, False, 0) - self._separators.append((controls_separator, separator)) + mini_separator = SpacedSeparator() + mini_separator.show() + self.mini_layout.layers_vbox.pack_start(mini_separator, False, False, 0) + + self._separators.append((controls_separator, separator, mini_separator)) def __layer_priority_changed_cb(self, unused_ges_layer, unused_pspec): """Handles the changing of a layer's priority.""" @@ -1198,11 +1328,13 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): def __update_separator(self, priority): """Sets the position of the separators in their parent.""" position = priority * 2 - controls_separator, layers_separator = self._separators[priority] + controls_separator, layers_separator, mini_layers_separator = self._separators[priority] vbox = self._layers_controls_vbox vbox.child_set_property(controls_separator, "position", position) vbox = self.layout.layers_vbox vbox.child_set_property(layers_separator, "position", position) + vbox = self.mini_layout.layers_vbox + vbox.child_set_property(mini_layers_separator, "position", position) def __update_layer(self, ges_layer): """Sets the position of the layer and its controls in their parent.""" @@ -1211,25 +1343,38 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): vbox.child_set_property(ges_layer.control_ui, "position", position) vbox = self.layout.layers_vbox vbox.child_set_property(ges_layer.ui, "position", position) + vbox = self.mini_layout.layers_vbox + vbox.child_set_property(ges_layer.mini_ui, "position", position) + + def __update_mini_timeline_height(self): + ges_layers = self.ges_timeline.get_layers() + # extra space to allow drag over separators of last layer. + height = (len(ges_layers) * MINI_LAYER_HEIGHT) + (2 * MINI_LAYER_HEIGHT) + self.mini_layout_container.props.height_request = height def _remove_layer(self, ges_layer): self.info("Removing layer: %s", ges_layer.props.priority) self.layout.layers_vbox.remove(ges_layer.ui) + self.mini_layout.layers_vbox.remove(ges_layer.mini_ui) self._layers_controls_vbox.remove(ges_layer.control_ui) ges_layer.disconnect_by_func(self.__layer_priority_changed_cb) # Remove extra separators. - controls_separator, separator = self._separators.pop() + controls_separator, separator, mini_layers_separator = self._separators.pop() self.layout.layers_vbox.remove(separator) + self.mini_layout.layers_vbox.remove(mini_layers_separator) self._layers_controls_vbox.remove(controls_separator) ges_layer.ui.release() ges_layer.ui = None + ges_layer.mini_ui.release() + ges_layer.mini_ui = None ges_layer.control_ui = None def _layer_removed_cb(self, unused_ges_timeline, ges_layer): self._remove_layer(ges_layer) self.__update_layers() + self.__update_mini_timeline_height() def separator_priority(self, separator): position = self.layout.layers_vbox.child_get_property(separator, "position") @@ -1248,11 +1393,12 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.update_position() self.editor_state.set_value("zoom-level", Zoomable.get_current_zoom_level()) - def set_best_zoom_ratio(self, allow_zoom_in=False): - """Sets the zoom level so that the entire timeline is in view.""" + def calc_best_zoom_ratio(self, mini=True): + """Returns the zoom ratio so that the entire timeline is in (mini)view.""" duration = 0 if not self.ges_timeline else self.ges_timeline.get_duration() - if not duration: - return + if not duration or (mini and not self.mini_layout_container.get_visible()): + # Maximum available width, the parent is TimelineContainer + return self.get_parent().get_allocated_width() # Add Gst.SECOND - 1 to the timeline duration to make sure the # last second of the timeline will be in view. @@ -1261,7 +1407,17 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.debug("Adjusting zoom for a timeline duration of %s secs", timeline_duration_s) - zoom_ratio = self.layout.get_allocation().width / timeline_duration_s + layout = self.mini_layout if mini else self.layout + zoom_ratio = layout.get_allocation().width / timeline_duration_s + return zoom_ratio + + def set_best_zoom_ratio(self, allow_zoom_in=False): + """Sets the zoom level so that the entire timeline is in view.""" + duration = 0 if not self.ges_timeline else self.ges_timeline.get_duration() + if not duration: + return + + zoom_ratio = self.calc_best_zoom_ratio(mini=False) nearest_zoom_level = Zoomable.compute_zoom_level(zoom_ratio) if nearest_zoom_level >= Zoomable.get_current_zoom_level() and not allow_zoom_in: # This means if we continue we'll zoom in. @@ -1296,7 +1452,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): return GES.EditMode.EDIT_TRIM return GES.EditMode.EDIT_NORMAL - def get_layer_at(self, y, prefer_ges_layer=None, past_middle_when_adjacent=False): + def get_layer_at(self, y, prefer_ges_layer=None, past_middle_when_adjacent=False, mini=False): ges_layers = self.ges_timeline.get_layers() if y < SEPARATOR_HEIGHT: # The cursor is at the top, above the first layer. @@ -1313,10 +1469,12 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): if past_middle_when_adjacent: index_preferred = prefer_ges_layer.get_priority() - height_preferred = prefer_ges_layer.ui.get_allocation().height + height_preferred = prefer_ges_layer.ui.get_allocation().height if not mini \ + else prefer_ges_layer.mini_ui.get_allocation().height for i, ges_layer in enumerate(ges_layers): - layer_rect = ges_layer.ui.get_allocation() + layer_rect = ges_layer.ui.get_allocation() if not mini \ + else ges_layer.mini_ui.get_allocation() layer_y = layer_rect.y layer_height = layer_rect.height if layer_y <= y < layer_y + layer_height: @@ -1343,7 +1501,10 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): # Choose a layer as close to prefer_ges_layer as possible. prefer_after = False - if layer_y + layer_height <= y < next_ges_layer.ui.get_allocation().y: + next_layer = next_ges_layer.ui if not mini \ + else next_ges_layer.mini_ui + + if layer_y + layer_height <= y < next_layer.get_allocation().y: # The cursor is between this layer and the one below. if prefer_after: ges_layer = next_ges_layer @@ -1357,12 +1518,13 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): for sep in self.__on_separators: set_state_flags_recurse(sep, Gtk.StateFlags.PRELIGHT, are_set=prelight) - def __drag_update(self, x, y): + def __drag_update(self, x, y, mini=False): """Updates a clip or asset drag operation. Args: x (int): The x coordinate relative to the layers box. y (int): The y coordinate relative to the layers box. + mini (bool): Event from Mini Timeline or Simple Timeline """ if not self.dragging_element: return @@ -1386,13 +1548,18 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): mode: GES.EditMode = self.__get_editing_mode() self.editing_context.set_mode(mode) + ratio = self.calc_best_zoom_ratio() if mini else None + x = x - int(self.__drag_start_x) + if self.editing_context.edge is GES.Edge.EDGE_END: - position = self.pixel_to_ns(x - int(self.__drag_start_x) + self.__clicked_handle.get_allocated_width()) + x = self.pixel_to_ns(x, zoomratio=ratio) + position = x + self.__clicked_handle.get_allocated_width() else: - position = self.pixel_to_ns(x - int(self.__drag_start_x)) + x = self.pixel_to_ns(x, zoomratio=ratio) + position = x self._set_separators_prelight(False) - res = self.get_layer_at(y, prefer_ges_layer=self._on_layer) + res = self.get_layer_at(y, prefer_ges_layer=self._on_layer, mini=mini) self._on_layer, self.__on_separators = res if (mode != GES.EditMode.EDIT_NORMAL or self.dragging_group.props.height > 1): @@ -1454,6 +1621,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): for ges_layer in self.ges_timeline.get_layers(): ges_layer.ui.check_media_types() + ges_layer.mini_ui.check_media_types() self._set_separators_prelight(False) self.__on_separators = [] @@ -1755,6 +1923,20 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): self.app.shortcuts.add("timeline.action-search", ["slash"], self.action_search, _("Action Search")) + # Cut Mode. + self.action_cut_mode = Gio.SimpleAction.new("action-cut-mode", None) + self.action_cut_mode.connect("activate", self.__action_cut_mode_cb) + group.add_action(self.action_cut_mode) + self.app.shortcuts.add("timeline.action-cut-mode", ["c"], + self.action_cut_mode, _("Action Cut Mode")) + + # Locked playhead mode, playhead is centered automatically. + self.action_locked_playhead_mode = Gio.SimpleAction.new("action-playhead-locked-mode", None) + self.action_locked_playhead_mode.connect("activate", self.__action_locked_playhead_mode_cb) + group.add_action(self.action_locked_playhead_mode) + self.app.shortcuts.add("timeline.action-playhead-locked-mode", ["p"], + self.action_locked_playhead_mode, _("Action Locked Playhead Mode")) + # Clips actions. self.delete_action = Gio.SimpleAction.new("delete-selected-clips", None) self.delete_action.connect("activate", self._delete_selected_cb) @@ -2448,3 +2630,17 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): self.app.project_manager.current_project.pipeline.simple_seek(position) self.app.gui.editor.timeline_ui.timeline.scroll_to_playhead(align=Gtk.Align.CENTER, when_not_in_view=True) + + def __action_cut_mode_cb(self, unused_action, unused_parameter): + if self.timeline.mini_layout_container.is_visible(): + self.timeline.mini_layout_container.hide() + else: + self.timeline.mini_layout_container.props.no_show_all = False + self.timeline.mini_layout_container.show_all() + + def __action_locked_playhead_mode_cb(self, unused_action, unused_parameter): + if self.timeline.playhead_locked: + self.timeline.playhead_locked = False + else: + self.timeline.playhead_locked = True + self.timeline.scroll_to_playhead() diff --git a/pitivi/utils/timeline.py b/pitivi/utils/timeline.py index 89f228416..2f90e1e67 100644 --- a/pitivi/utils/timeline.py +++ b/pitivi/utils/timeline.py @@ -115,11 +115,13 @@ class Selection(GObject.Object, Loggable): old_selection = self._clips self._clips = selection + from pitivi.utils.ui import set_state_flags_recurse for obj, selected in self.__get_selection_changes(old_selection): obj.selected.selected = selected if obj.ui: - from pitivi.utils.ui import set_state_flags_recurse set_state_flags_recurse(obj.ui, Gtk.StateFlags.SELECTED, are_set=selected) + if obj.mini_ui: + set_state_flags_recurse(obj.mini_ui, Gtk.StateFlags.SELECTED, are_set=selected) for element in obj.get_children(False): if isinstance(obj, (GES.BaseEffect, GES.TextOverlay)): @@ -457,19 +459,20 @@ class Zoomable: cls.zoom_range) ** (1.0 / 3.0)) * cls.zoom_steps) @classmethod - def pixel_to_ns(cls, pixel): + def pixel_to_ns(cls, pixel, zoomratio=None): """Returns the duration equivalent of the specified pixel.""" - return int(pixel * Gst.SECOND / cls.zoomratio) + zoomratio = cls.zoomratio if zoomratio is None else zoomratio + return int(pixel * Gst.SECOND / zoomratio) @classmethod - def ns_to_pixel(cls, duration): + def ns_to_pixel(cls, duration, zoomratio=None): """Returns the pixel equivalent of the specified duration.""" # Here, a long time ago (206f3a05), a pissed programmer said: # DIE YOU CUNTMUNCH CLOCK_TIME_NONE UBER STUPIDITY OF CRACK BINDINGS !! + zoomratio = cls.zoomratio if zoomratio is None else zoomratio if duration == Gst.CLOCK_TIME_NONE: return 0 - - return int((float(duration) / Gst.SECOND) * cls.zoomratio) + return int((float(duration) / Gst.SECOND) * zoomratio) @classmethod def ns_to_pixel_accurate(cls, duration): diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index cf591ddbe..61d2ab62e 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -57,6 +57,7 @@ PLAYHEAD_COLOR = (255, 0, 0) SNAPBAR_WIDTH = 5 SNAPBAR_COLOR = (127, 153, 204) LAYER_HEIGHT = 130 +MINI_LAYER_HEIGHT = 25 # The space between two layers. SEPARATOR_HEIGHT = 1 @@ -227,6 +228,7 @@ EDITOR_PERSPECTIVE_CSS = """ .VideoPreviewer:selected, .AudioPreviewer:selected, + .MiniPreviewer:selected, .TitlePreviewer:selected { opacity: 0.15; } diff --git a/tests/common.py b/tests/common.py index 3a7dbe297..3bf4ae69d 100644 --- a/tests/common.py +++ b/tests/common.py @@ -513,18 +513,25 @@ class TestCase(unittest.TestCase, Loggable): def check_priorities_and_positions(self, timeline, ges_layers, expected_priorities): layers_vbox = timeline.layout.layers_vbox + mini_layers_vbox = timeline.mini_layout.layers_vbox # Check the layers priorities. priorities = [ges_layer.props.priority for ges_layer in ges_layers] self.assertListEqual(priorities, expected_priorities) + expected_positions = [priority * 2 + 1 + for priority in expected_priorities] + # Check the positions of the Layer widgets. positions = [layers_vbox.child_get_property(ges_layer.ui, "position") for ges_layer in ges_layers] - expected_positions = [priority * 2 + 1 - for priority in expected_priorities] self.assertListEqual(positions, expected_positions, layers_vbox.get_children()) + # Check the positions of the MiniLayer widgets. + positions = [mini_layers_vbox.child_get_property(ges_layer.mini_ui, "position") + for ges_layer in ges_layers] + self.assertListEqual(positions, expected_positions, mini_layers_vbox.get_children()) + # Check the positions of the LayerControl widgets. controls_vbox = timeline._layers_controls_vbox positions = [controls_vbox.child_get_property(ges_layer.control_ui, "position") @@ -534,15 +541,21 @@ class TestCase(unittest.TestCase, Loggable): # Check the number of the separators. count = len(ges_layers) + 1 self.assertEqual(len(timeline._separators), count) - controls_separators, layers_separators = list(zip(*timeline._separators)) - # Check the positions of the LayerControl separators. expected_positions = [2 * index for index in range(count)] + controls_separators, layers_separators, mini_layers_separators = list(zip(*timeline._separators)) + + # Check the positions of the Layer separators. positions = [layers_vbox.child_get_property(separator, "position") for separator in layers_separators] self.assertListEqual(positions, expected_positions) - # Check the positions of the Layer separators. + # Check the positions of the MiniLayer separators. + positions = [mini_layers_vbox.child_get_property(separator, "position") + for separator in mini_layers_separators] + self.assertListEqual(positions, expected_positions) + + # Check the positions of the LayerControl separators. positions = [controls_vbox.child_get_property(separator, "position") for separator in controls_separators] self.assertListEqual(positions, expected_positions) @@ -662,4 +675,5 @@ def create_test_clip(clip_type): clip = clip_type() clip.selected = Selected() clip.ui = None + clip.mini_ui = None return clip diff --git a/tests/test_timeline_elements.py b/tests/test_timeline_elements.py index dfb1be41c..bddb7ce85 100644 --- a/tests/test_timeline_elements.py +++ b/tests/test_timeline_elements.py @@ -29,6 +29,7 @@ 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 SELECT +from pitivi.utils.timeline import UNSELECT from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import LAYER_HEIGHT from tests import common @@ -513,3 +514,18 @@ class TestClip(common.TestCase): ges_object = GObject.new(gtype) widget = widget_class(ges_layer.ui, ges_object) self.assertEqual(ges_object.ui, widget, widget_class) + + def test_mini_selection(self): + """Checks whether both ui and mini_ui gets selected.""" + timeline_container = common.create_timeline_container() + timeline = timeline_container.timeline + + clip1, = self.add_clips_simple(timeline, 1) + + timeline.selection.set_selection([clip1], SELECT) + self.assertTrue(clip1.ui.get_state_flags() & Gtk.StateFlags.SELECTED) + self.assertTrue(clip1.mini_ui.get_state_flags() & Gtk.StateFlags.SELECTED) + + timeline.selection.set_selection([clip1], UNSELECT) + self.assertFalse(clip1.ui.get_state_flags() & Gtk.StateFlags.SELECTED) + self.assertFalse(clip1.mini_ui.get_state_flags() & Gtk.StateFlags.SELECTED) diff --git a/tests/test_timeline_layer.py b/tests/test_timeline_layer.py index 68aaef965..2d2485823 100644 --- a/tests/test_timeline_layer.py +++ b/tests/test_timeline_layer.py @@ -20,7 +20,7 @@ from unittest import mock from gi.repository import GES from pitivi.timeline.layer import AUDIO_ICONS -from pitivi.timeline.layer import Layer +from pitivi.timeline.layer import FullLayer from pitivi.timeline.layer import VIDEO_ICONS from pitivi.utils.ui import LAYER_HEIGHT from tests import common @@ -31,7 +31,7 @@ class TestLayerControl(common.TestCase): def test_name(self): timeline = mock.MagicMock() ges_layer = GES.Layer() - layer = Layer(ges_layer, timeline) + layer = FullLayer(ges_layer, timeline) self.assertEqual(layer.get_name(), "Layer 0", "Default name generation failed") ges_layer.set_meta("audio::name", "a") @@ -46,7 +46,7 @@ class TestLayerControl(common.TestCase): def test_name_meaningful(self): timeline = mock.MagicMock() ges_layer = GES.Layer() - layer = Layer(ges_layer, timeline) + layer = FullLayer(ges_layer, timeline) layer.set_name("Layer 0x") self.assertEqual(layer.get_name(), "Layer 0x") @@ -160,7 +160,7 @@ class TestLayer(common.TestCase): # the layer will use check_media_types which updates the # height of layer.control_ui, which now it should not be set. self.assertFalse(hasattr(ges_layer, "control_ui")) - unused_layer = Layer(ges_layer, timeline) + unused_layer = FullLayer(ges_layer, timeline) @common.setup_timeline def test_layer_heights(self): diff --git a/tests/test_undo_timeline.py b/tests/test_undo_timeline.py index 86eaead4e..1dcdf5a8b 100644 --- a/tests/test_undo_timeline.py +++ b/tests/test_undo_timeline.py @@ -25,7 +25,7 @@ from gi.repository import Gst from gi.repository import GstController from gi.repository import Gtk -from pitivi.timeline.layer import Layer +from pitivi.timeline.layer import FullLayer from pitivi.undo.base import PropertyChangedAction from pitivi.undo.project import AssetAddedAction from pitivi.undo.timeline import ClipAdded @@ -320,7 +320,7 @@ class TestLayerObserver(common.TestCase): @common.setup_timeline def test_layer_renamed(self): - layer = Layer(self.layer, timeline=mock.Mock()) + layer = FullLayer(self.layer, timeline=mock.Mock()) self.assertIsNone(layer._name_if_set()) with self.app.action_log.started("change layer name"): -- GitLab From b67bebbbfd73b696d29a2a1734ca83bc9e336e74 Mon Sep 17 00:00:00 2001 From: yatinmaan Date: Tue, 19 Jul 2022 07:37:32 +0530 Subject: [PATCH 002/132] X Hacky fix --- pitivi/timeline/markers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pitivi/timeline/markers.py b/pitivi/timeline/markers.py index 674e5c3fe..adb0b5f45 100644 --- a/pitivi/timeline/markers.py +++ b/pitivi/timeline/markers.py @@ -190,6 +190,11 @@ class MarkersBox(Gtk.EventBox, Zoomable, Loggable): self.__markers_container.connect("marker-removed", self._marker_removed_cb) self.__markers_container.connect("marker-moved", self._marker_moved_cb) + # Hacky fix for 2x calls to release() + self.__markers_container.connect("marker-added", self._marker_added_cb) + self.__markers_container.connect("marker-removed", self._marker_removed_cb) + self.__markers_container.connect("marker-moved", self._marker_moved_cb) + def release(self): if self.__markers_container: self.__markers_container.disconnect_by_func(self._marker_added_cb) -- GitLab From 16923809b980b48925262a485d07c6cf6f7f5477 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 3 Jun 2022 12:48:28 +0530 Subject: [PATCH 003/132] Replace deprecated GtkButtonBox with GtkBox --- data/ui/clipmediaprops.ui | 3 +-- data/ui/cliptransformation.ui | 4 ++-- data/ui/elementsettingsdialog.ui | 3 +-- data/ui/filelisterrordialog.ui | 3 +-- data/ui/greeter.ui | 4 ++-- data/ui/markerpopover.ui | 3 +-- data/ui/medialibrary.ui | 8 ++++---- data/ui/preferences.ui | 7 +++---- data/ui/projectsettings.ui | 3 +-- data/ui/renderingdialog.ui | 3 +-- data/ui/renderingprogress.ui | 3 +-- data/ui/trackerperspective.ui | 9 ++++----- pitivi/clipproperties.py | 2 +- pitivi/timeline/layer.py | 4 ++-- 14 files changed, 25 insertions(+), 34 deletions(-) diff --git a/data/ui/clipmediaprops.ui b/data/ui/clipmediaprops.ui index 3db1de50b..001fe710c 100644 --- a/data/ui/clipmediaprops.ui +++ b/data/ui/clipmediaprops.ui @@ -14,10 +14,9 @@ vertical 12 - + True False - end _Cancel diff --git a/data/ui/cliptransformation.ui b/data/ui/cliptransformation.ui index 0b48498b9..c091976d2 100644 --- a/data/ui/cliptransformation.ui +++ b/data/ui/cliptransformation.ui @@ -163,11 +163,11 @@ - + True False center - expand + < diff --git a/data/ui/elementsettingsdialog.ui b/data/ui/elementsettingsdialog.ui index 6e7a7e2d7..74c04c7af 100644 --- a/data/ui/elementsettingsdialog.ui +++ b/data/ui/elementsettingsdialog.ui @@ -15,10 +15,9 @@ vertical 12 - + True False - end Reset all diff --git a/data/ui/filelisterrordialog.ui b/data/ui/filelisterrordialog.ui index 37c7e20b0..14f8a7cc5 100644 --- a/data/ui/filelisterrordialog.ui +++ b/data/ui/filelisterrordialog.ui @@ -16,10 +16,9 @@ vertical 12 - + True False - end OK diff --git a/data/ui/greeter.ui b/data/ui/greeter.ui index ba3819381..d645ebeb0 100644 --- a/data/ui/greeter.ui +++ b/data/ui/greeter.ui @@ -106,10 +106,10 @@ False True - + False 6 - end + diff --git a/data/ui/markerpopover.ui b/data/ui/markerpopover.ui index 31eccaef2..4e24b4fc7 100644 --- a/data/ui/markerpopover.ui +++ b/data/ui/markerpopover.ui @@ -30,11 +30,10 @@ - + True False True - start gtk-remove diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index 896a59866..76cc2993f 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -191,11 +191,11 @@ warning True - + False 5 6 - end + True @@ -250,12 +250,12 @@ False other - + False 5 vertical 6 - end + diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index 2aabe3436..8542c061d 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -18,9 +18,8 @@ vertical 8 - + False - end Reset to Factory Settings @@ -135,12 +134,12 @@ False warning - + False 5 vertical 6 - end + diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index c0acb3b4d..815a7ae44 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -69,10 +69,9 @@ vertical 12 - + True False - end Cancel diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index 128dd82bb..f958610d3 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -50,10 +50,9 @@ vertical 18 - + True False - end Render diff --git a/data/ui/renderingprogress.ui b/data/ui/renderingprogress.ui index 50de7120d..3bcba9c06 100644 --- a/data/ui/renderingprogress.ui +++ b/data/ui/renderingprogress.ui @@ -18,10 +18,9 @@ vertical 12 - + True False - end Pause diff --git a/data/ui/trackerperspective.ui b/data/ui/trackerperspective.ui index c357436e3..1c8bc1773 100644 --- a/data/ui/trackerperspective.ui +++ b/data/ui/trackerperspective.ui @@ -109,7 +109,7 @@ - + True False True @@ -157,10 +157,9 @@ True False - + False 6 - end @@ -275,11 +274,11 @@ 20 vertical - + True False True - center + linked True diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index 86281480c..a1a82935e 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -599,7 +599,7 @@ class EffectProperties(Gtk.Expander, Loggable): self.add_effect_button.set_popover(self.effect_popover) self.add_effect_button.props.halign = Gtk.Align.CENTER - self.object_tracker_box = Gtk.ButtonBox() + self.object_tracker_box = Gtk.Box() self.object_tracker_box.props.halign = Gtk.Align.CENTER self.cover_popover: Optional[Gtk.Popover] = None diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 80f5e32ec..91fe362ba 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -116,10 +116,10 @@ class LayerControls(Gtk.EventBox, Loggable): self.video_button.connect("clicked", self.__video_button_clicked_cb) self.__update_video_button() - control_box = Gtk.ButtonBox() - control_box.set_layout(Gtk.ButtonBoxStyle.EXPAND) + control_box = Gtk.Box() control_box.add(self.video_button) control_box.add(self.audio_button) + control_box.get_style_context().add_class("linked") name_row.pack_start(control_box, False, False, 0) space = Gtk.Label() -- GitLab From 9239358d8929aa4182d6caf7a4faa0e37bcb3a46 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 19 Jun 2022 13:08:11 +0530 Subject: [PATCH 004/132] Replace deprecated border_width --- data/ui/alignmentprogress.ui | 5 ++++- data/ui/clipcompositing.ui | 5 ++++- data/ui/clipmediaprops.ui | 5 ++++- data/ui/customwidgets/alpha.ui | 5 ++++- .../frei0r-filter-3-point-color-balance.ui | 5 ++++- .../customwidgets/frei0r-filter-alphaspot.ui | 5 ++++- data/ui/elementsettingsdialog.ui | 5 ++++- data/ui/filelisterrordialog.ui | 5 ++++- data/ui/medialibrary.ui | 20 +++++++++++++++---- data/ui/preferences.ui | 10 ++++++++-- data/ui/projectsettings.ui | 20 +++++++++++++++---- data/ui/renderingdialog.ui | 15 +++++++++++--- data/ui/renderingprogress.ui | 5 ++++- data/ui/trackerperspective.ui | 5 ++++- pitivi/clip_properties/markers.py | 5 ++++- pitivi/clipproperties.py | 5 ++++- pitivi/dialogs/missingasset.py | 5 ++++- pitivi/dialogs/prefs.py | 5 ++++- pitivi/project.py | 10 ++++++++-- pitivi/tabsmanager.py | 5 ++++- pitivi/transitions.py | 5 ++++- pitivi/utils/widgets.py | 6 ++++-- tests/plugins/test_alpha.ui | 5 ++++- 23 files changed, 132 insertions(+), 34 deletions(-) diff --git a/data/ui/alignmentprogress.ui b/data/ui/alignmentprogress.ui index 12de80929..efe9f75d2 100644 --- a/data/ui/alignmentprogress.ui +++ b/data/ui/alignmentprogress.ui @@ -4,7 +4,10 @@ False - 12 + 12 + 12 + 12 + 12 Auto-Alignment Starting True center-on-parent diff --git a/data/ui/clipcompositing.ui b/data/ui/clipcompositing.ui index e08850e49..e362b2ca5 100644 --- a/data/ui/clipcompositing.ui +++ b/data/ui/clipcompositing.ui @@ -30,7 +30,10 @@ False start start - 10 + 10 + 10 + 10 + 10 10 6 diff --git a/data/ui/clipmediaprops.ui b/data/ui/clipmediaprops.ui index 001fe710c..217695571 100644 --- a/data/ui/clipmediaprops.ui +++ b/data/ui/clipmediaprops.ui @@ -4,7 +4,10 @@ False - 5 + 5 + 5 + 5 + 5 Clip Properties dialog diff --git a/data/ui/customwidgets/alpha.ui b/data/ui/customwidgets/alpha.ui index c261d1fa4..f63243afd 100644 --- a/data/ui/customwidgets/alpha.ui +++ b/data/ui/customwidgets/alpha.ui @@ -77,7 +77,10 @@ True False - 12 + 12 + 12 + 12 + 12 8 6 diff --git a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui index a694d6209..66f78a041 100644 --- a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui +++ b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui @@ -66,7 +66,10 @@ True False - 8 + 8 + 8 + 8 + 8 8 8 diff --git a/data/ui/customwidgets/frei0r-filter-alphaspot.ui b/data/ui/customwidgets/frei0r-filter-alphaspot.ui index 8721ad4c7..ad2a27f26 100644 --- a/data/ui/customwidgets/frei0r-filter-alphaspot.ui +++ b/data/ui/customwidgets/frei0r-filter-alphaspot.ui @@ -93,7 +93,10 @@ True False - 12 + 12 + 12 + 12 + 12 8 6 diff --git a/data/ui/elementsettingsdialog.ui b/data/ui/elementsettingsdialog.ui index 74c04c7af..a001f1c66 100644 --- a/data/ui/elementsettingsdialog.ui +++ b/data/ui/elementsettingsdialog.ui @@ -4,7 +4,6 @@ False - 12 Properties for <element> True dialog @@ -14,6 +13,10 @@ False vertical 12 + 12 + 12 + 12 + 12 True diff --git a/data/ui/filelisterrordialog.ui b/data/ui/filelisterrordialog.ui index 14f8a7cc5..fb2ad5676 100644 --- a/data/ui/filelisterrordialog.ui +++ b/data/ui/filelisterrordialog.ui @@ -5,7 +5,6 @@ True False - 12 dialog @@ -15,6 +14,10 @@ False vertical 12 + 12 + 12 + 12 + 12 True diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index 76cc2993f..9f6b6e6d7 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -193,7 +193,10 @@ False - 5 + 5 + 5 + 5 + 5 6 @@ -218,7 +221,10 @@ False - 8 + 8 + 8 + 8 + 8 16 @@ -252,7 +258,10 @@ False - 5 + 5 + 5 + 5 + 5 vertical 6 @@ -269,7 +278,10 @@ False - 8 + 8 + 8 + 8 + 8 16 diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index 8542c061d..6f5dd31eb 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -136,7 +136,10 @@ False - 5 + 5 + 5 + 5 + 5 vertical 6 @@ -153,7 +156,10 @@ False - 8 + 8 + 8 + 8 + 8 True diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index 815a7ae44..1463dbd63 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -57,7 +57,6 @@ False - 5 Project Settings center-on-parent dialog @@ -68,6 +67,10 @@ False vertical 12 + 5 + 5 + 5 + 5 True @@ -128,7 +131,10 @@ True False - 12 + 12 + 12 + 12 + 12 vertical 12 @@ -405,7 +411,10 @@ True False start - 12 + 12 + 12 + 12 + 12 6 6 @@ -518,7 +527,10 @@ True False - 12 + 12 + 12 + 12 + 12 vertical 12 diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index f958610d3..91a9c8ca1 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -36,7 +36,6 @@ False - 18 Render True center-always @@ -49,6 +48,10 @@ False vertical 18 + 18 + 18 + 18 + 18 True @@ -386,7 +389,10 @@ This option is a good trade-off between quality of the rendered video and stabil True False - 12 + 12 + 12 + 12 + 12 vertical 6 @@ -552,7 +558,10 @@ This option is a good trade-off between quality of the rendered video and stabil True False - 12 + 12 + 12 + 12 + 12 vertical 6 diff --git a/data/ui/renderingprogress.ui b/data/ui/renderingprogress.ui index 3bcba9c06..88486645d 100644 --- a/data/ui/renderingprogress.ui +++ b/data/ui/renderingprogress.ui @@ -4,7 +4,6 @@ False - 12 Rendering True center-on-parent @@ -17,6 +16,10 @@ False vertical 12 + 12 + 12 + 12 + 12 True diff --git a/data/ui/trackerperspective.ui b/data/ui/trackerperspective.ui index 1c8bc1773..65bfbddfa 100644 --- a/data/ui/trackerperspective.ui +++ b/data/ui/trackerperspective.ui @@ -363,7 +363,10 @@ True False center - 12 + 12 + 12 + 12 + 12 6 diff --git a/pitivi/clip_properties/markers.py b/pitivi/clip_properties/markers.py index fe23b0491..03d722867 100644 --- a/pitivi/clip_properties/markers.py +++ b/pitivi/clip_properties/markers.py @@ -94,7 +94,10 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): continue row_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=SPACING) - row_box.set_border_width(SPACING) + row_box.set_margin_top(SPACING) + row_box.set_margin_bottom(SPACING) + row_box.set_margin_start(SPACING) + row_box.set_margin_end(SPACING) row_box.show() row_size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.VERTICAL) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index a1a82935e..19fc0ade0 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -285,7 +285,10 @@ class TimeProperties(Gtk.Expander, Loggable): grid = Gtk.Grid.new() grid.props.row_spacing = SPACING grid.props.column_spacing = SPACING - grid.props.border_width = SPACING + grid.props.margin_top = SPACING + grid.props.margin_bottom = SPACING + grid.props.margin_start = SPACING + grid.props.margin_end = SPACING self.add(grid) self._speed_adjustment = Gtk.Adjustment() diff --git a/pitivi/dialogs/missingasset.py b/pitivi/dialogs/missingasset.py index 0b898a3fb..e8517d8d8 100644 --- a/pitivi/dialogs/missingasset.py +++ b/pitivi/dialogs/missingasset.py @@ -45,7 +45,10 @@ class MissingAssetDialog(Gtk.Dialog, Loggable): self.set_modal(True) self.add_buttons(_("Cancel"), Gtk.ResponseType.CANCEL, _("Open"), Gtk.ResponseType.OK) - self.set_border_width(SPACING * 2) + self.set_margin_bottom(SPACING * 2) + self.set_margin_end(SPACING * 2) + self.set_margin_start(SPACING * 2) + self.set_margin_top(SPACING * 2) self.get_content_area().set_spacing(SPACING) self.set_transient_for(app.gui) self.set_default_response(Gtk.ResponseType.OK) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index fc228c75f..de44c3fad 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -231,7 +231,10 @@ class PreferencesDialog(Loggable): def _create_props_container(self, prefs): container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - container.set_border_width(SPACING) + container.set_margin_top(SPACING) + container.set_margin_bottom(SPACING) + container.set_margin_start(SPACING) + container.set_margin_end(SPACING) listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) diff --git a/pitivi/project.py b/pitivi/project.py index 9c10938ec..9e2a8eeca 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -219,7 +219,10 @@ class ProjectManager(GObject.Object, Loggable): hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=SPACING * 2) hbox.pack_start(image, False, True, 0) hbox.pack_start(vbox, True, True, 0) - hbox.set_border_width(SPACING) + hbox.set_margin_top(SPACING) + hbox.set_margin_bottom(SPACING) + hbox.set_margin_start(SPACING) + hbox.set_margin_end(SPACING) # stuff the hbox in the dialog content_area = dialog.get_content_area() @@ -316,7 +319,10 @@ class ProjectManager(GObject.Object, Loggable): hbox.set_orientation(Gtk.Orientation.HORIZONTAL) hbox.pack_start(image, False, False, 0) hbox.pack_start(vbox, True, True, 0) - hbox.set_border_width(SPACING) + hbox.set_margin_top(SPACING) + hbox.set_margin_bottom(SPACING) + hbox.set_margin_start(SPACING) + hbox.set_margin_end(SPACING) # stuff the hbox in the dialog content_area = dialog.get_content_area() diff --git a/pitivi/tabsmanager.py b/pitivi/tabsmanager.py index 2a8c332d2..36570fe16 100644 --- a/pitivi/tabsmanager.py +++ b/pitivi/tabsmanager.py @@ -36,7 +36,10 @@ class BaseTabs(Gtk.Notebook, Loggable): def __init__(self, app): Gtk.Notebook.__init__(self) Loggable.__init__(self) - self.set_border_width(SPACING) + self.set_margin_top(SPACING) + self.set_margin_bottom(SPACING) + self.set_margin_start(SPACING) + self.set_margin_end(SPACING) self.set_scrollable(True) self.settings = app.settings notebook_widget_settings = self.get_settings() diff --git a/pitivi/transitions.py b/pitivi/transitions.py index a7510fdff..8ad76ae82 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -62,7 +62,10 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.searchbar = Gtk.Box() self.searchbar.set_orientation(Gtk.Orientation.HORIZONTAL) # Prevents being flush against the notebook - self.searchbar.set_border_width(3) + self.searchbar.set_margin_top(3) + self.searchbar.set_margin_bottom(3) + self.searchbar.set_margin_start(3) + self.searchbar.set_margin_end(3) self.search_entry = Gtk.Entry() self.search_entry.set_icon_from_icon_name( Gtk.EntryIconPosition.SECONDARY, "edit-clear-symbolic") diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 9153abf85..9458403c8 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -114,7 +114,6 @@ class TextWidget(Gtk.Box, DynamicWidget): DynamicWidget.__init__(self, default) self.set_orientation(Gtk.Orientation.HORIZONTAL) - self.set_border_width(0) self.set_spacing(0) if widget is None: if choices: @@ -841,7 +840,10 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): grid = Gtk.Grid() grid.props.row_spacing = SPACING grid.props.column_spacing = SPACING - grid.props.border_width = SPACING + grid.props.margin_top = SPACING + grid.props.margin_bottom = SPACING + grid.props.margin_start = SPACING + grid.props.margin_end = SPACING element_name = None if isinstance(self.element, Gst.Element): diff --git a/tests/plugins/test_alpha.ui b/tests/plugins/test_alpha.ui index e231be7b2..4d791a0e3 100644 --- a/tests/plugins/test_alpha.ui +++ b/tests/plugins/test_alpha.ui @@ -27,7 +27,10 @@ True False - 6 + 6 + 6 + 6 + 6 6 6 -- GitLab From 23eecaab097fe6fbcf8619b737a271a9d3dcf59e Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Mon, 20 Jun 2022 22:32:06 +0530 Subject: [PATCH 005/132] Replace deprecated stock buttons --- data/ui/markerpopover.ui | 3 +-- data/ui/project_info.ui | 1 - data/ui/renderingdialog.ui | 4 ++-- data/ui/trackerperspective.ui | 9 +++------ pitivi/editorperspective.py | 4 ++-- pitivi/utils/widgets.py | 2 +- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/data/ui/markerpopover.ui b/data/ui/markerpopover.ui index 4e24b4fc7..01703cdc6 100644 --- a/data/ui/markerpopover.ui +++ b/data/ui/markerpopover.ui @@ -36,11 +36,10 @@ True - gtk-remove + Remove True True True - True - False - True 0 - True - True 1 diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index 9f6b6e6d7..bb2576bc2 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -29,7 +29,6 @@ - False True @@ -48,7 +47,6 @@ - False True @@ -67,7 +65,6 @@ - False True @@ -87,14 +84,11 @@ - False True - False - True 3 @@ -124,7 +118,6 @@ - False True @@ -143,7 +136,6 @@ - False True @@ -152,11 +144,13 @@ True False 5 + True True True 3 + True starred-symbolic edit-clear-symbolic @@ -198,23 +192,20 @@ 5 5 6 - + fill True True + fill True - False - True 0 - False - True 1 @@ -226,23 +217,22 @@ 8 8 16 + fill True False True 0 + fill - False - True 0 True - True 0 @@ -264,14 +254,12 @@ 5 vertical 6 - + fill - False - True 1 @@ -283,6 +271,7 @@ 8 8 16 + fill True @@ -290,17 +279,15 @@ Add media to your project by dragging files and folders here or by using the "Import" button. True 0 + True + fill - False - True 0 - True - True 0 diff --git a/data/ui/pluginpreferencesrow.ui b/data/ui/pluginpreferencesrow.ui index 3c6371cb6..d4f550551 100644 --- a/data/ui/pluginpreferencesrow.ui +++ b/data/ui/pluginpreferencesrow.ui @@ -18,15 +18,16 @@ True False vertical + fill True False 0 + True + fill - True - True 0 @@ -36,20 +37,18 @@ False True 0 + True + fill - True - True 1 - False - True 0 @@ -61,8 +60,6 @@ 6 - False - False end 1 diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index 6f5dd31eb..bceb7ecd2 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -20,6 +20,7 @@ False + fill Reset to Factory Settings @@ -28,12 +29,11 @@ False True True + fill Reset all settings to their default values - False - True 0 True @@ -48,10 +48,9 @@ True Revert all settings to the previous values (before you opened the preferences dialog) + fill - False - True 1 @@ -62,17 +61,14 @@ True True True + fill - False - True 2 - False - True end 2 @@ -87,10 +83,10 @@ False True stack + True + fill - False - True 0 @@ -99,10 +95,10 @@ True False vertical + True + fill - False - True 1 @@ -111,21 +107,18 @@ True False True + fill crossfade - False - True 2 - True - True 0 @@ -133,6 +126,7 @@ False warning + fill False @@ -142,14 +136,12 @@ 5 vertical 6 - + fill - False - True 1 @@ -166,24 +158,20 @@ False Some changes will not take effect until you restart Pitivi True + True + fill - False - True 0 - True - True 0 - False - True 1 diff --git a/data/ui/project_info.ui b/data/ui/project_info.ui index ebebbeb27..68265a904 100644 --- a/data/ui/project_info.ui +++ b/data/ui/project_info.ui @@ -12,10 +12,9 @@ False 12 True + fill - False - True 0 @@ -30,6 +29,7 @@ 12 True vertical + fill True @@ -38,15 +38,11 @@ True - False - True 0 - False - True 1 @@ -55,10 +51,12 @@ True False vertical + fill True False + fill project_name_label @@ -67,8 +65,6 @@ start - False - True 0 @@ -82,15 +78,11 @@ True - False - True 1 - False - True 0 @@ -105,15 +97,11 @@ True - False - True 1 - False - True 2 diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index 1463dbd63..7c2feca19 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -75,6 +75,7 @@ True False + fill Cancel @@ -83,8 +84,6 @@ True - False - False 0 @@ -96,15 +95,11 @@ True - False - False 1 - False - True end 0 @@ -116,6 +111,7 @@ False 6 12 + fill True @@ -154,8 +150,6 @@ - False - False 0 @@ -164,6 +158,7 @@ True False True + fill True @@ -171,8 +166,6 @@ - False - True 1 @@ -182,6 +175,7 @@ True True none + fill True @@ -191,15 +185,12 @@ - False - True 2 - False - False + 0 @@ -209,12 +200,14 @@ False vertical 12 + fill True False vertical 6 + fill True @@ -226,8 +219,6 @@ - False - True 0 @@ -245,8 +236,6 @@ True - False - False 0 @@ -257,8 +246,6 @@ × - False - False 1 @@ -271,8 +258,6 @@ True - False - False 2 @@ -280,18 +265,15 @@ True False + fill pixels - False - True 3 - False - False 1 @@ -308,15 +290,11 @@ - False - False 2 - False - True 0 @@ -326,7 +304,7 @@ False start vertical - 6 + 6 fill True @@ -338,8 +316,6 @@ - False - True 0 @@ -347,6 +323,7 @@ True False + fill @@ -355,8 +332,6 @@ - False - True 1 @@ -365,15 +340,11 @@ - False - True 1 - False - True 1 @@ -539,12 +510,14 @@ False vertical 12 + fill True False vertical 6 + fill True @@ -556,8 +529,6 @@ - False - True 0 @@ -577,8 +548,6 @@ 1 - False - False 0 @@ -589,8 +558,6 @@ × - False - False 1 @@ -605,8 +572,6 @@ 1 - False - False 2 @@ -614,18 +579,15 @@ True False + fill pixels - False - True 3 - False - False 1 @@ -640,8 +602,6 @@ - False - False 2 @@ -653,25 +613,20 @@ True False 1 + fill - False - True 3 - False - True 0 - False - True 1 @@ -879,8 +834,6 @@ - False - True 3 diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index ba03dbe6b..e81d5c9e3 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -56,6 +56,7 @@ True False + fill Render @@ -68,15 +69,11 @@ - False - False 1 - False - True end 4 @@ -87,6 +84,8 @@ False True True + fill + fill 6 12 @@ -152,6 +151,7 @@ True right preset_popover + fill True @@ -187,8 +187,6 @@ - False - True 0 @@ -208,8 +206,6 @@ - False - True 1 @@ -269,8 +265,6 @@ - False - True 0 @@ -282,11 +276,10 @@ help_icon none True + fill - False - True 1 @@ -322,8 +315,6 @@ This option is a good trade-off between quality of the rendered video and stabil True - False - True 0 @@ -339,8 +330,6 @@ This option is a good trade-off between quality of the rendered video and stabil True - False - True 1 @@ -357,8 +346,6 @@ This option is a good trade-off between quality of the rendered video and stabil True - False - True 2 @@ -406,8 +393,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True 0 @@ -425,8 +410,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False 1 @@ -441,8 +424,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False end 2 @@ -461,8 +442,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False end 3 @@ -478,8 +457,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True end 4 @@ -498,8 +475,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False end 5 @@ -515,8 +490,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True end 6 @@ -575,8 +548,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True 0 @@ -607,8 +578,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False 0 @@ -627,15 +596,11 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True 1 - False - False 1 @@ -649,8 +614,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False 2 @@ -664,8 +627,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False end 3 @@ -684,8 +645,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False end 4 @@ -701,8 +660,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True end 5 @@ -726,8 +683,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - False end 6 @@ -743,8 +698,6 @@ This option is a good trade-off between quality of the rendered video and stabil - False - True end 7 @@ -836,8 +789,6 @@ This option is a good trade-off between quality of the rendered video and stabil - True - True 0 diff --git a/data/ui/renderingprogress.ui b/data/ui/renderingprogress.ui index 88486645d..8e4e15be9 100644 --- a/data/ui/renderingprogress.ui +++ b/data/ui/renderingprogress.ui @@ -24,6 +24,7 @@ True False + fill Pause @@ -33,8 +34,6 @@ - False - False 0 @@ -47,8 +46,6 @@ - False - False 1 @@ -58,11 +55,10 @@ True True True + fill - False - True 2 True @@ -74,10 +70,10 @@ True True + True + fill - True - True 3 True @@ -88,18 +84,15 @@ True True True + fill - False - True 4 - False - True end 0 @@ -114,10 +107,9 @@ True 50 0 + fill - False - True 0 @@ -127,10 +119,9 @@ False Initializing... True + fill - False - True 3 @@ -164,8 +155,6 @@ - False - True 4 diff --git a/data/ui/timelinetoolbar.ui b/data/ui/timelinetoolbar.ui index d5bfe99ce..82f72a80f 100644 --- a/data/ui/timelinetoolbar.ui +++ b/data/ui/timelinetoolbar.ui @@ -20,7 +20,6 @@ scissors-symbolic - False True @@ -35,7 +34,6 @@ edit-delete-symbolic - False True @@ -50,7 +48,6 @@ attach-audio-symbolic - False True @@ -65,7 +62,6 @@ detach-audio-symbolic - False True @@ -80,7 +76,6 @@ edit-cut-symbolic - False True @@ -95,7 +90,6 @@ edit-copy-symbolic - False True @@ -110,7 +104,6 @@ edit-paste-symbolic - False True @@ -125,7 +118,6 @@ stopwatch-symbolic - False True @@ -141,7 +133,6 @@ When enabled, adjacent clips automatically move to fill gaps. align-tool-symbolic - False True diff --git a/data/ui/titleeditor.ui b/data/ui/titleeditor.ui index d120565bc..32fa0807e 100644 --- a/data/ui/titleeditor.ui +++ b/data/ui/titleeditor.ui @@ -25,6 +25,8 @@ True False etched-in + True + fill True @@ -44,10 +46,9 @@ True word -1 + fill - False - True 0 @@ -69,11 +70,10 @@ False Choose a font + fill - False - True 0 @@ -87,11 +87,10 @@ True Pick a text color rgb(239,41,41) + fill - False - True 1 @@ -102,13 +101,12 @@ False 0 none + fill - False - True 2 @@ -122,11 +120,10 @@ True Pick a background color rgb(255,255,255) + fill - False - True 3 @@ -137,13 +134,12 @@ False 0 none + fill - False - True 4 @@ -156,11 +152,10 @@ True Pick an outline color rgba(0,0,0,0) + fill - False - True 5 @@ -171,20 +166,17 @@ False 0 none + fill - False - True 6 - False - True 1 @@ -200,8 +192,6 @@ - False - True 2 @@ -218,8 +208,6 @@ 0 - False - True 3 @@ -312,8 +300,6 @@ - False - True 4 @@ -321,8 +307,6 @@ - True - True 2 diff --git a/data/ui/trackerperspective.ui b/data/ui/trackerperspective.ui index 557016874..475c70675 100644 --- a/data/ui/trackerperspective.ui +++ b/data/ui/trackerperspective.ui @@ -67,8 +67,6 @@ center - False - True 0 @@ -77,6 +75,7 @@ True True True + fill never True True @@ -103,8 +102,6 @@ - True - True 1 @@ -123,8 +120,6 @@ - False - False 0 @@ -138,15 +133,11 @@ - False - False 1 - False - True 2 @@ -154,6 +145,7 @@ True False + fill False @@ -163,8 +155,6 @@ - False - False 0 @@ -178,10 +168,9 @@ False dialog-information-symbolic 5 + fill - False - True 0 @@ -193,32 +182,25 @@ True 0 30 + fill - False - True 1 - False - False 0 - False - True 3 - False - False - 0 + 0 @@ -227,9 +209,7 @@ False - False - False - 1 + 1 @@ -245,6 +225,7 @@ 0 none False + fill True @@ -257,8 +238,6 @@ - False - True 0 @@ -271,12 +250,14 @@ 20 20 vertical + fill True False True linked + fill True @@ -284,11 +265,11 @@ True Go back one frame seek_backward_icon + True + fill - True - True 0 @@ -299,11 +280,11 @@ True play_icon True + True + fill - True - True 1 @@ -314,11 +295,11 @@ True Go forward one frame seek_forward_icon + True + fill - True - True 2 @@ -327,15 +308,11 @@ - False - True 0 - False - True 1 @@ -349,10 +326,9 @@ pos_adj True False + fill - False - True 2 @@ -377,8 +353,6 @@ - False - True 0 @@ -390,8 +364,6 @@ 3 - False - False 6 1 @@ -403,10 +375,10 @@ True True + True + fill - True - True 2 @@ -416,25 +388,20 @@ True True True + fill - False - True 3 - False - True 3 - True - True 2 -- GitLab From 5311a44f5c161fda9aca4c85b2c0fc08951e58e6 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 2 Jul 2022 18:41:58 +0530 Subject: [PATCH 007/132] Drop use of GtkAlignment --- data/ui/clipmediaprops.ui | 275 ++++++----- data/ui/projectsettings.ui | 926 ++++++++++++++++++------------------- data/ui/renderingdialog.ui | 514 ++++++++++---------- 3 files changed, 826 insertions(+), 889 deletions(-) diff --git a/data/ui/clipmediaprops.ui b/data/ui/clipmediaprops.ui index bb67c8e74..b371650f3 100644 --- a/data/ui/clipmediaprops.ui +++ b/data/ui/clipmediaprops.ui @@ -66,124 +66,115 @@ True fill - + True False + True - + True False - True + start - + True False - start - - - True - False - fill - - - 0 - - - - - True - False - x - fill - - - 1 - - - - - True - False - fill - - - 2 - - + fill - 1 - 0 + 0 - - Size (pixels) - True - True - False - start - 0 - True - - - 0 - 0 - - - - - Frame rate - True - True - False - start - 0 - True - - - 0 - 1 - - - - - Pixel aspect ratio - True - True - False - start - 0 - True - - - 0 - 2 - - - - + True False - start + x + fill - 1 - 2 + 1 - + True False - start + fill - 1 - 1 + 2 + + 1 + 0 + + + + + Size (pixels) + True + True + False + start + True + + + 0 + 0 + + + + + Frame rate + True + True + False + start + True + + + 0 + 1 + + + + + Pixel aspect ratio + True + True + False + start + True + + + 0 + 2 + + + + + True + False + start + + + 1 + 2 + + + + + True + False + start + + + 1 + 1 + @@ -211,67 +202,59 @@ True fill - + True False + True - + True False - True - - - True - False - start - - - 1 - 0 - - - - - True - False - start - - - 1 - 1 - - - - - Sample rate - True - True - False - start - 0 - True - - - 0 - 1 - - - - - Channels - True - True - False - start - 0.5 - True - - - 0 - 0 - - + start + + + 1 + 0 + + + + + True + False + start + + + 1 + 1 + + + + + Sample rate + True + True + False + start + True + + + 0 + 1 + + + + + Channels + True + True + False + start + True + + 0 + 0 + diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index 7c2feca19..a4909566f 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -118,33 +118,96 @@ False 0 - + True False - 0 - 6 + 12 + 12 + 18 + 12 + vertical + 12 - + + True + False + end + 6 + + + True + False + start + Preset: + + + + + + 0 + + + + + True + False + True + fill + + + True + + + + + 1 + + + + + True + True + True + none + fill + + + True + False + open-menu-symbolic + + + + + 2 + + + + + + 0 + + + + True False - 12 - 12 - 12 - 12 vertical 12 + fill - + True False - end + vertical 6 + fill - + True False start - Preset: + Size: @@ -154,15 +217,54 @@ - + True False - True - fill - - + 6 + + + True True + + adjustment1 + True + + + 0 + + + + + True + False + × + + + 1 + + + + + True + True + + adjustment2 + True + + + 2 + + + + + True + False + fill + pixels + + 3 + @@ -170,19 +272,15 @@ - + + Constrain proportions True True - True - none - fill - - - True - False - open-menu-symbolic - - + False + Maintain aspect ratio + start + True + 2 @@ -190,165 +288,59 @@ - 0 - + True False + start vertical - 12 + 6 fill - + True False - vertical - 6 - fill - - - True - False - start - Size: - - - - - - 0 - - - - - True - False - 6 - - - True - True - - adjustment1 - True - - - 0 - - - - - True - False - × - - - 1 - - - - - True - True - - adjustment2 - True - - - 2 - - - - - True - False - fill - pixels - - - 3 - - - - - 1 - - - - - Constrain proportions - True - True - False - Maintain aspect ratio - start - 0.5 - True - - - - 2 - - + start + Frame rate: + + + 0 - + True False - start - vertical - 6 fill - - - True - False - start - Frame rate: - - - - - - 0 - - - - - True - False - fill - - - - 0 - - - - - 1 - - + fill - + + + 0 + 1 + + + 1 + + 1 + @@ -372,101 +364,94 @@ False 0 - + + True False - 6 + start + 12 + 12 + 18 + 12 + 6 + 6 + + + True + True + 10 + True + + + + 1 + 0 + + - - + True False - start - 12 - 12 - 12 - 12 - 6 - 6 - - - True - True - 10 - True - - - - 1 - 0 - - - - - True - False - start - Author: - - - 0 - 0 - - - - - True - False - start - Year: - - - 2 - 0 - - - - - True - True - start - 4 - - 1900 - adjustment3 - True - 1900 - - - 3 - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - + start + Author: + + + 0 + 0 + + + + + True + False + start + Year: + + 2 + 0 + + + + + True + True + start + 4 + + 1900 + adjustment3 + True + 1900 + + + 3 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + @@ -490,131 +475,92 @@ False 0 - + True False - 6 + 12 + 12 + 18 + 12 + vertical + 12 - + True False - 12 - 12 - 12 - 12 vertical 12 + fill - + True False vertical - 12 + 6 fill - + + True + False + start + Scaled proxies resolution: + + + + + + 0 + + + + True False - vertical 6 - fill - + True - False - start - Scaled proxies resolution: - - - + True + + 1 + adjustment4 + True + 1 0 - + True False - 6 - - - True - True - - 1 - adjustment4 - True - 1 - - - 0 - - - - - True - False - × - - - 1 - - - - - True - True - - 1 - adjustment5 - True - 1 - - - 2 - - - - - True - False - fill - pixels - - - 3 - - + × 1 - - Constrain proportions + True True - False - start - True - + + 1 + adjustment5 + True + 1 2 - + True - True - <a href='#'>Proxy Preferences</a> - True - False - 1 + False fill - + pixels 3 @@ -622,15 +568,47 @@ - 0 + 1 + + + + + Constrain proportions + True + True + False + start + True + + + + 2 + + + + + True + True + <a href='#'>Proxy Preferences</a> + True + False + 1 + fill + + + + 3 - 1 + 0 + + 1 + @@ -653,160 +631,154 @@ False 0 - + + True False - 12 - 12 - 18 - 12 + 6 + 6 + 12 + 12 + 18 + 12 - - + True False - 6 - 6 - - - True - False - start - Title: - - - - - - 0 - 0 - 4 - - - - - True - False - start - 6 - Action: - - - - - - 0 - 2 - 4 - - - - - True - True - - 1 - adjustment8 - True - 1 - - - 0 - 3 - - - - - True - True - - 1 - adjustment9 - True - 1 - - - 2 - 3 - - - - - True - True - - 1 - adjustment6 - True - 1 - - - 0 - 1 - - - - - True - True - - 1 - adjustment7 - True - 1 - - - 2 - 1 - - - - - True - False - % - 0 - - - 3 - 1 - - - - - True - False - % - 0 - - - 3 - 3 - - - - - True - False - × - - - 1 - 1 - - - - - True - False - × - - - 1 - 3 - - + start + Title: + + + + + + 0 + 0 + 4 + + + + + True + False + start + 6 + Action: + + + + + + 0 + 2 + 4 + + + + + True + True + + 1 + adjustment8 + True + 1 + + + 0 + 3 + + + + + True + True + + 1 + adjustment9 + True + 1 + + + 2 + 3 + + + + + True + True + + 1 + adjustment6 + True + 1 + + + 0 + 1 + + + + + True + True + + 1 + adjustment7 + True + 1 + + + 2 + 1 + + + + + True + False + % + 0 + + + 3 + 1 + + + + + True + False + % + 0 + + + 3 + 3 + + + + + True + False + × + + + 1 + 1 + + + + + True + False + × + + 1 + 3 + diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index e81d5c9e3..142319c4c 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -368,133 +368,125 @@ This option is a good trade-off between quality of the rendered video and stabil False 0 - + True False - 12 + 12 + 12 + 24 + 12 + vertical + 6 - + True False - 12 - 12 - 12 - 12 - vertical - 6 - - - True - False - start - Channels: - - - - - - 0 - - - - - True - False - start - - - - - 0 - - - - - 1 - - - - - Advanced... - True - True - True - end - 1 - - - - end - 2 - - + start + Channels: + + + + + + 0 + + + + + True + False + start + - - True - False - start - - - - - 0 - - - - - end - 3 - - - - - True - False - start - Codec: - - - - - - end - 4 - + + + 0 + + + + 1 + + + + + Advanced... + True + True + True + end + + + + end + 2 + + + + + True + False + start + - - True - False - start - - - - - 0 - - - - - end - 5 - + + + 0 + + + + end + 3 + + + + + True + False + start + Codec: + + + + + + end + 4 + + + + + True + False + start + - - True - False - start - Sample rate: - - - - - - end - 6 - + + + 0 + + + end + 5 + + + + + True + False + start + Sample rate: + + + + + + end + 6 + @@ -505,7 +497,6 @@ This option is a good trade-off between quality of the rendered video and stabil True False start - 0 True True @@ -523,186 +514,178 @@ This option is a good trade-off between quality of the rendered video and stabil False 0 - + True False - 12 + 12 + 12 + 24 + 12 + vertical + 6 - + True False - 12 - 12 - 12 - 12 - vertical - 6 + start + Scale: + + + + + + 0 + + + + + True + False + start + 12 - + True - False + True start - Scale: - - - + + 1.0 + False + False + adjustment1 + 1 + True + 1 + + + + Scale + + 0 - + True False start - 12 - - - True - True - start - - 1.0 - False - False - adjustment1 - 1 - True - 1 - - - - Scale - - - - - 0 - - - - - True - False - start - 1000 x 1000 - 12 - 0 - - - Height - - + 1000 x 1000 + 12 + + + Height - - 1 - 1 + + + 1 + + + + + Project Settings... + True + True + True + end + + + + 2 + + + + + Advanced... + True + True + True + end + + + + end + 3 + + + + + True + False + start + - - Project Settings... - True - True - True - end - - - - 2 - - - - - Advanced... - True - True - True - end - - - - end - 3 - - - - - True - False - start - - - - - 0 - - - - - end - 4 - - - - - True - False - start - Codec: - - - - - - end - 5 - + + + 0 + + + + end + 4 + + + + + True + False + start + Codec: + + + + + + end + 5 + + + + + True + False + start + - - True - False - start - - - - - 0 - - - - - Framerate - - - - - end - 6 - + + + 0 + - - - True - False - start - Frame rate: - - - + + + Framerate - - end - 7 - + + end + 6 + + + + + True + False + start + Frame rate: + + + + + + end + 7 + @@ -713,7 +696,6 @@ This option is a good trade-off between quality of the rendered video and stabil True False start - 0 True True -- GitLab From e94ae7262dda48a81c6d37ec5354a3f24c85c15a Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 7 Jul 2022 18:42:51 +0530 Subject: [PATCH 008/132] Remove deprecated app_paintable property --- data/ui/medialibrary.ui | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index bb2576bc2..64d0966b2 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -180,7 +180,6 @@ True - True False warning True @@ -242,7 +241,6 @@ True - True False other -- GitLab From 9f6a36372048ebd43f90518d3c8e06478f3e1080 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Mon, 11 Jul 2022 22:09:38 +0530 Subject: [PATCH 009/132] Miscellaneous fixes --- data/ui/clipcolor.ui | 8 ++++---- pitivi/utils/widgets.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/ui/clipcolor.ui b/data/ui/clipcolor.ui index 4f1c05d1f..89fd5f86d 100644 --- a/data/ui/clipcolor.ui +++ b/data/ui/clipcolor.ui @@ -6,10 +6,10 @@ True False start - 12 - 12 - 12 - 12 + 12 + 12 + 12 + 12 5 diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 63c562163..523d45292 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -570,10 +570,10 @@ class FontWidget(Gtk.FontButton, DynamicWidget): self.connect("font-set", callback, *args) def set_widget_value(self, font_name): - self.set_font_name(font_name) + self.set_font(font_name) def get_widget_value(self): - return self.get_font_name() + return self.get_font() class InputValidationWidget(Gtk.Box, DynamicWidget): -- GitLab From b5bde3716b783ada3de95c907e0f11d43db0fc7d Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Mon, 11 Jul 2022 23:37:30 +0530 Subject: [PATCH 010/132] Change GTK Version to 4.x --- pitivi/check.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pitivi/check.py b/pitivi/check.py index 69e74723a..c74529b6c 100644 --- a/pitivi/check.py +++ b/pitivi/check.py @@ -388,10 +388,8 @@ def initialize_modules(): sys.exit(1) require_version("Gtk", GTK_API_VERSION) - require_version("Gdk", GTK_API_VERSION) - from gi.repository import Gdk - Gdk.init([]) from gi.repository import Gtk + Gtk.init() # Monkey patch deprecated methods to use the new variant by default Gtk.Layout.get_vadjustment = Gtk.Scrollable.get_vadjustment @@ -456,7 +454,7 @@ def initialize_modules(): GST_API_VERSION = "1.0" GST_VERSION = "1.17.90" # FIXME Remove checks in proxy.py and utils/markers.py once we bump to >= 1.19.2 -GTK_API_VERSION = "3.0" +GTK_API_VERSION = "4.0" GLIB_API_VERSION = "2.0" HARD_DEPENDENCIES = [GICheck(version_required="3.20.0"), CairoDependency(version_required="1.10.0"), @@ -470,7 +468,7 @@ HARD_DEPENDENCIES = [GICheck(version_required="3.20.0"), GIDependency("GstVideo", apiversion=GST_API_VERSION), GtkDependency("Gtk", apiversion=GTK_API_VERSION, - version_required="3.20.0"), + version_required="4.6.0"), ClassicDependency("numpy"), GIDependency("Gio", apiversion="2.0"), GstPluginDependency("gtk"), -- GitLab From 932e223bd361789cde029c42ee141c53909f953c Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Mon, 11 Jul 2022 23:46:45 +0530 Subject: [PATCH 011/132] Replace deprecated pack_start and pack_end --- pitivi/action_search_bar.py | 7 ++- pitivi/clip_properties/markers.py | 21 ++++--- pitivi/clipproperties.py | 90 +++++++++++++++++++-------- pitivi/dialogs/filelisterrordialog.py | 2 +- pitivi/dialogs/missingasset.py | 16 ++--- pitivi/dialogs/prefs.py | 47 ++++++++------ pitivi/dialogs/projectsettings.py | 4 +- pitivi/editorperspective.py | 4 +- pitivi/effects.py | 37 ++++++++--- pitivi/greeterperspective.py | 6 +- pitivi/interactiveintro.py | 19 +++++- pitivi/mediafilespreviewer.py | 16 +++-- pitivi/medialibrary.py | 80 +++++++++++++++++------- pitivi/project.py | 29 ++++++--- pitivi/timeline/elements.py | 8 ++- pitivi/timeline/layer.py | 18 +++--- pitivi/timeline/timeline.py | 20 +++--- pitivi/trackerperspective.py | 6 +- pitivi/transitions.py | 16 +++-- pitivi/utils/custom_effect_widgets.py | 4 +- pitivi/utils/widgets.py | 30 +++++---- pitivi/viewer/viewer.py | 54 +++++++++------- 22 files changed, 354 insertions(+), 180 deletions(-) diff --git a/pitivi/action_search_bar.py b/pitivi/action_search_bar.py index c81897b36..b9ced0f05 100644 --- a/pitivi/action_search_bar.py +++ b/pitivi/action_search_bar.py @@ -41,16 +41,19 @@ class ActionSearchBar(Gtk.Window): self.entry = Gtk.SearchEntry() self.results_window = Gtk.ScrolledWindow() self.results_window.props.can_focus = False + self.results_window.set_hexpand(True) + self.results_window.set_halign(Gtk.Align.FILL) clear_styles(self.entry) self.setup_results_window() self.entry.props.placeholder_text = _("Search Action") + self.entry.set_hexpand(True) self.entry.connect("key-press-event", self._entry_key_press_event_cb) self.entry.connect("changed", self._entry_changed_cb) self.treeview.connect("row-activated", self._treeview_row_activated_cb) - self.vbox.pack_start(self.entry, True, True, 0) - self.vbox.pack_start(self.results_window, True, True, 0) + self.vbox.prepend(self.entry) + self.vbox.prepend(self.results_window) def setup_results_window(self): self.list_model = Gtk.ListStore(str, int, Gdk.ModifierType, Gio.SimpleAction, object, bool, bool) diff --git a/pitivi/clip_properties/markers.py b/pitivi/clip_properties/markers.py index 03d722867..3ebb86724 100644 --- a/pitivi/clip_properties/markers.py +++ b/pitivi/clip_properties/markers.py @@ -104,40 +104,43 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): child_type = child.get_track_type() name = ClipMarkersProperties.TRACK_TYPES[child_type] label = Gtk.Label(label=name) - row_box.pack_start(label, False, False, 0) + row_box.prepend(label) label.show() labels_size_group.add_widget(label) row_size_group.add_widget(label) label.props.valign = Gtk.Align.START controls_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=SPACING) + controls_box.set_vexpand(True) + controls_box.set_valign(Gtk.Align.FILL) controls_box.show() selection_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=SPACING) list_store = Gtk.ListStore(str, str) list_combo = Gtk.ComboBox.new_with_model(list_store) renderer_text = Gtk.CellRendererText() - list_combo.pack_start(renderer_text, True) + renderer_text.set_hexpand(True) + list_combo.prepend(renderer_text) list_combo.add_attribute(renderer_text, "text", 1) list_combo.set_id_column(0) - selection_box.pack_start(list_combo, False, False, 0) + selection_box.prepend(list_combo) list_combo.show() combos_size_group.add_widget(list_combo) row_size_group.add_widget(list_combo) snap_toggle = Gtk.CheckButton.new_with_label(_("Magnetic")) - selection_box.pack_start(snap_toggle, False, False, 0) + selection_box.prepend(snap_toggle) if GES_MARKERS_SNAPPABLE: snap_toggle.show() - controls_box.pack_start(selection_box, False, False, 0) + controls_box.prepend(selection_box) if isinstance(child, GES.AudioSource) and "librosa" not in MISSING_SOFT_DEPS: container = self._create_beat_detection_ui() - controls_box.pack_start(container, False, False, 0) + controls_box.prepend(container) audio_source = child - row_box.pack_start(controls_box, True, True, 0) + row_box.prepend(controls_box) manager = child.markers_manager list_combo.connect("changed", self._combo_changed_cb, child, snap_toggle) @@ -152,9 +155,9 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): # Display audio marker settings below the video ones, # matching how they're shown on the timeline. if child_type == GES.TrackType.AUDIO: - self.expander_box.pack_end(row_box, False, False, 0) + self.expander_box.append(row_box) else: - self.expander_box.pack_start(row_box, False, False, 0) + self.expander_box.prepend(row_box) self._set_audio_source(audio_source) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index 19fc0ade0..f5f7b4050 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -107,39 +107,39 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): self.clips_box = Gtk.Box() self.clips_box.set_orientation(Gtk.Orientation.VERTICAL) self.clips_box.show() - vbox.pack_start(self.clips_box, False, False, 0) + vbox.prepend(self.clips_box) self.transformation_expander = TransformationProperties(app) self.transformation_expander.set_vexpand(False) - vbox.pack_start(self.transformation_expander, False, False, 0) + vbox.prepend(self.transformation_expander) self.speed_expander = TimeProperties(app) self.speed_expander.set_vexpand(False) if in_devel(): - vbox.pack_start(self.speed_expander, False, False, 0) + vbox.prepend(self.speed_expander) self.title_expander = TitleProperties(app) self.title_expander.set_vexpand(False) - vbox.pack_start(self.title_expander, False, False, 0) + vbox.prepend(self.title_expander) self.color_expander = ColorProperties(app) self.color_expander.set_vexpand(False) - vbox.pack_start(self.color_expander, False, False, 0) + vbox.prepend(self.color_expander) self.compositing_expander = CompositingProperties(app) self.compositing_expander.set_vexpand(False) - vbox.pack_start(self.compositing_expander, False, False, 0) + vbox.prepend(self.compositing_expander) self.effect_expander = EffectProperties(app) self.effect_expander.set_vexpand(False) - vbox.pack_start(self.effect_expander, False, False, 0) + vbox.prepend(self.effect_expander) self.marker_expander = ClipMarkersProperties(app) self.marker_expander.set_vexpand(False) - vbox.pack_start(self.marker_expander, False, False, 0) + vbox.prepend(self.marker_expander) self.helper_box = self.create_helper_box() - self.clips_box.pack_start(self.helper_box, False, False, 0) + self.clips_box.prepend(self.helper_box) disable_scroll(vbox) @@ -162,17 +162,29 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): label = Gtk.Label(label=_("Select a clip on the timeline to configure its properties and effects or create a new clip:")) label.set_line_wrap(True) label.set_xalign(0) - box.pack_start(label, False, False, SPACING) + label.props.margin_top = SPACING + label.props.margin_bottom = SPACING + label.props.margin_start = SPACING + label.props.margin_end = SPACING + box.append(label) self._title_button = Gtk.Button() self._title_button.set_label(_("Create a title clip")) self._title_button.connect("clicked", self.create_title_clip_cb) - box.pack_start(self._title_button, False, False, SPACING) + self._title_button.props.margin_top = SPACING + self._title_button.props.margin_bottom = SPACING + self._title_button.props.margin_start = SPACING + self._title_button.props.margin_end = SPACING + box.append(self._title_button) self._color_button = Gtk.Button() self._color_button.set_label(_("Create a color clip")) self._color_button.connect("clicked", self.create_color_clip_cb) - box.pack_start(self._color_button, False, False, SPACING) + self._color_button.props.margin_top = SPACING + self._color_button.props.margin_bottom = SPACING + self._color_button.props.margin_start = SPACING + self._color_button.props.margin_end = SPACING + box.append(self._color_button) box.show_all() return box @@ -298,6 +310,10 @@ class TimeProperties(Gtk.Expander, Loggable): self._speed_spin_button = Gtk.SpinButton.new(adjustment=self._speed_adjustment, climb_rate=2, digits=2) self._speed_spin_button.set_increments(.1, 1) self._speed_spin_button.set_numeric(True) + self._speed_spin_button.props.margin_top = PADDING + self._speed_spin_button.props.margin_bottom = PADDING + self._speed_spin_button.props.margin_start = PADDING + self._speed_spin_button.props.margin_end = PADDING self._speed_scale_adjustment = Gtk.Adjustment() self._speed_scale_adjustment.props.lower = self._rate_to_linear(1 / MAX_RATE) @@ -307,6 +323,10 @@ class TimeProperties(Gtk.Expander, Loggable): self._speed_scale.set_size_request(width=200, height=-1) self._speed_scale.props.draw_value = False self._speed_scale.props.show_fill_level = False + self._speed_scale.props.margin_top = PADDING + self._speed_scale.props.margin_bottom = PADDING + self._speed_scale.props.margin_start = PADDING + self._speed_scale.props.margin_end = PADDING linear = self._rate_to_linear(1 / 4) self._speed_scale.add_mark(linear, Gtk.PositionType.BOTTOM, "¼") @@ -317,8 +337,9 @@ class TimeProperties(Gtk.Expander, Loggable): self._speed_scale.add_mark(linear, Gtk.PositionType.BOTTOM, "{}".format(rate)) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - hbox.pack_start(self._speed_spin_button, False, False, PADDING) - hbox.pack_start(self._speed_scale, False, False, PADDING) + + hbox.prepend(self._speed_spin_button) + hbox.prepend(self._speed_scale) self.__add_widget_to_grid(grid, _("Speed"), hbox, self._speed_reset_button_clicked_cb, 0) self.__setting_rate = False @@ -601,22 +622,30 @@ class EffectProperties(Gtk.Expander, Loggable): self.add_effect_button = Gtk.MenuButton(_("Add Effect")) self.add_effect_button.set_popover(self.effect_popover) self.add_effect_button.props.halign = Gtk.Align.CENTER + self.add_effect_button.props.margin_top = PADDING + self.add_effect_button.props.margin_bottom = PADDING + self.add_effect_button.props.margin_start = PADDING + self.add_effect_button.props.margin_end = PADDING self.object_tracker_box = Gtk.Box() self.object_tracker_box.props.halign = Gtk.Align.CENTER + self.object_tracker_box.props.margin_top = PADDING + self.object_tracker_box.props.margin_bottom = PADDING + self.object_tracker_box.props.margin_start = PADDING + self.object_tracker_box.props.margin_end = PADDING self.cover_popover: Optional[Gtk.Popover] = None self.cover_object_button: Optional[Gtk.MenuButton] = None if "cvtracker" not in MISSING_SOFT_DEPS: self.cover_object_button = Gtk.MenuButton(_("Cover Object")) - self.object_tracker_box.pack_start(self.cover_object_button, False, False, 0) + self.object_tracker_box.prepend(self.cover_object_button) self.drag_dest_set(Gtk.DestDefaults.DROP, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) - self.expander_box.pack_start(self.effects_listbox, False, False, 0) - self.expander_box.pack_start(self.add_effect_button, False, False, PADDING) - self.expander_box.pack_start(self.object_tracker_box, False, False, PADDING) + self.expander_box.prepend(self.effects_listbox) + self.expander_box.prepend(self.add_effect_button) + self.expander_box.prepend(self.object_tracker_box) self.add(self.expander_box) @@ -648,6 +677,10 @@ class EffectProperties(Gtk.Expander, Loggable): toggle = Gtk.CheckButton() toggle.props.active = effect.props.active + toggle.props.margin_top = PADDING + toggle.props.margin_bottom = PADDING + toggle.props.margin_start = PADDING + toggle.props.margin_end = PADDING effect_info = self.app.effects.get_info(effect) effect_label = Gtk.Label(effect_info.human_name) @@ -672,13 +705,18 @@ class EffectProperties(Gtk.Expander, Loggable): row_widgets_box = Gtk.Box() row_drag_icon = Gtk.Image.new_from_pixbuf(self.drag_lines_pixbuf) - row_widgets_box.pack_start(row_drag_icon, False, False, PADDING) - row_widgets_box.pack_start(toggle, False, False, PADDING) - row_widgets_box.pack_start(expander, True, True, PADDING) - row_widgets_box.pack_end(remove_effect_button, False, False, 0) + row_drag_icon.props.margin_top = PADDING + row_drag_icon.props.margin_bottom = PADDING + row_drag_icon.props.margin_start = PADDING + row_drag_icon.props.margin_end = PADDING + + row_widgets_box.prepend(row_drag_icon) + row_widgets_box.prepend(toggle) + row_widgets_box.prepend(expander) + row_widgets_box.append(remove_effect_button) - vbox.pack_start(row_widgets_box, False, False, 0) - vbox.pack_start(config_ui_revealer, False, False, 0) + vbox.prepend(row_widgets_box) + vbox.prepend(config_ui_revealer) event_box = Gtk.EventBox() event_box.add(vbox) @@ -949,7 +987,9 @@ class TransformationProperties(Gtk.Expander, Loggable): alignment_editor_container = self.builder.get_object("clip_alignment") self.alignment_editor = AlignmentEditor() self.alignment_editor.connect("align", self.__alignment_editor_align_cb) - alignment_editor_container.pack_start(self.alignment_editor, True, True, 0) + self.alignment_editor.set_hexpand(True) + self.alignment_editor.set_halign(Gtk.Align.FILL) + alignment_editor_container.prepend(self.alignment_editor) self.__control_bindings = {} # Used to make sure self.__control_bindings_changed doesn't get called diff --git a/pitivi/dialogs/filelisterrordialog.py b/pitivi/dialogs/filelisterrordialog.py index b7ae5c501..2f0a40fec 100644 --- a/pitivi/dialogs/filelisterrordialog.py +++ b/pitivi/dialogs/filelisterrordialog.py @@ -59,7 +59,7 @@ class FileListErrorDialog(GObject.Object, Loggable): """ self.debug("Uri: %s, reason: %s, extra: %s", uri, reason, extra) exp = self.__create_file_expander(uri, reason, extra) - self.errorvbox.pack_start(exp, False, False, 0) + self.errorvbox.prepend(exp) if len(self.errorvbox.get_children()) < 3: exp.set_expanded(True) # Let's save the user some clicks exp.show_all() diff --git a/pitivi/dialogs/missingasset.py b/pitivi/dialogs/missingasset.py index e8517d8d8..1a9b49593 100644 --- a/pitivi/dialogs/missingasset.py +++ b/pitivi/dialogs/missingasset.py @@ -60,7 +60,7 @@ class MissingAssetDialog(Gtk.Dialog, Loggable): label_start = Gtk.Label() label_start.set_markup(_("The following file could not be found:")) label_start.set_xalign(0) - vbox.pack_start(label_start, False, False, 0) + vbox.prepend(label_start) hbox = Gtk.Box() hbox.set_orientation(Gtk.Orientation.HORIZONTAL) @@ -71,27 +71,29 @@ class MissingAssetDialog(Gtk.Dialog, Loggable): label_asset_info.set_markup(beautify_missing_asset(asset)) label_asset_info.set_xalign(0) label_asset_info.set_yalign(0) - hbox.pack_start(label_asset_info, False, False, 0) + hbox.prepend(label_asset_info) unused_small_thumb, large_thumb = AssetThumbnail.get_thumbnails_from_xdg_cache(uri) if large_thumb: self.debug("A thumbnail file was found for %s", uri) thumbnail = Gtk.Image.new_from_pixbuf(large_thumb) - hbox.pack_end(thumbnail, False, False, 0) + hbox.append(thumbnail) - vbox.pack_start(hbox, False, False, 0) + vbox.prepend(hbox) label_end = Gtk.Label() label_end.set_markup(_("Please specify its new location:")) label_end.set_xalign(0) label_end.set_margin_top(PADDING) - vbox.pack_start(label_end, False, False, 0) + vbox.prepend(label_end) - self.get_content_area().pack_start(vbox, False, False, 0) + self.get_content_area().prepend(vbox) vbox.show_all() self._chooser = self.__setup_file_chooser(uri, app.settings) - self.get_content_area().pack_start(self._chooser, True, True, 0) + self._chooser.set_hexpand(True) + self._chooser.set_halign(Gtk.Align.FILL) + self.get_content_area().prepend(self._chooser) self._chooser.show() # If the window is too big, the window manager will resize it so that diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index de44c3fad..a9cd2b413 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -241,7 +241,7 @@ class PreferencesDialog(Loggable): listbox.props.margin = PADDING * 2 listbox.get_style_context().add_class('prefs_list') - container.pack_start(listbox, False, False, 0) + container.prepend(listbox) label_size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) prop_size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) @@ -254,6 +254,8 @@ class PreferencesDialog(Loggable): label_widget.props.margin_end = PADDING * 3 label_widget.props.margin_top = PADDING * 2 label_widget.props.margin_bottom = PADDING * 2 + label_widget.set_hexpand(True) + label_widget.set_halign(Gtk.Align.FILL) label_size_group.add_widget(label_widget) widget.props.margin_end = PADDING * 3 @@ -261,16 +263,20 @@ class PreferencesDialog(Loggable): widget.props.margin_bottom = PADDING * 2 prop_size_group.add_widget(widget) - box.pack_start(label_widget, True, True, 0) - box.pack_start(widget, False, False, 0) + box.prepend(label_widget) + box.prepend(widget) if revert_widget: - box.pack_start(revert_widget, False, False, 0) + box.prepend(revert_widget) if extra_widget: box1 = box box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - box.pack_start(box1, False, False, 0) - box.pack_start(extra_widget, False, False, SPACING) + box.prepend(box1) + extra_widget.props.margin_top = SPACING + extra_widget.props.margin_bottom = SPACING + extra_widget.props.margin_start = SPACING + extra_widget.props.margin_end = SPACING + box.append(extra_widget) box.props.margin_start = PADDING * 3 @@ -329,9 +335,9 @@ class PreferencesDialog(Loggable): self.proxy_height_widget.set_widget_value(self.app.settings.default_scaled_proxy_height) self.widgets["default_scaled_proxy_height"] = self.proxy_height_widget size_box = Gtk.Box(spacing=SPACING) - size_box.pack_start(self.proxy_width_widget, False, False, 0) - size_box.pack_start(Gtk.Label("×"), False, False, 0) - size_box.pack_start(self.proxy_height_widget, False, False, 0) + size_box.prepend(self.proxy_width_widget) + size_box.prepend(Gtk.Label("×")) + size_box.prepend(self.proxy_height_widget) size_box.set_tooltip_text(_("This resolution will be used as the" " default target resolution for new projects and projects missing" " scaled proxy meta-data.")) @@ -349,7 +355,7 @@ class PreferencesDialog(Loggable): container = self._create_props_container(prefs) - container.pack_start(self.proxy_infobar, False, False, 0) + container.prepend(self.proxy_infobar) self._add_page("_proxies", container) @@ -449,11 +455,14 @@ class PreferencesDialog(Loggable): title_label.props.margin_end = PADDING * 3 title_label.props.margin_top = PADDING * 2 title_label.props.margin_bottom = PADDING * 2 + title_label.set_hexpand(True) + title_label.set_halign(Gtk.Align.FILL) self.description_size_group.add_widget(title_label) accel_label.props.xalign = 0 accel_label.props.margin_start = PADDING * 3 accel_label.props.margin_end = PADDING * 2 + accel_label.set_hexpand(True) self.accel_size_group.add_widget(accel_label) # Add the third column with the reset button. @@ -471,9 +480,9 @@ class PreferencesDialog(Loggable): # Pack the three widgets above into a row and add to parent_box. contents_box = Gtk.Box() - contents_box.pack_start(title_label, True, True, 0) - contents_box.pack_start(accel_label, True, False, 0) - contents_box.pack_start(button, False, False, 0) + contents_box.prepend(title_label) + contents_box.prepend(accel_label) + contents_box.prepend(button) return contents_box @@ -883,8 +892,10 @@ class PluginsBox(Gtk.ListBox): inner_box.props.margin_top = PADDING * 3 inner_box.props.margin_bottom = PADDING inner_box.props.margin_end = PADDING * 2 - inner_box.pack_start(header, True, True, 0) - inner_box.pack_start(button, False, False, 0) + inner_box.set_hexpand(True) + inner_box.set_halign(Gtk.Align.FILL) + inner_box.prepend(header) + inner_box.prepend(button) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.add(inner_box) @@ -936,9 +947,9 @@ class PluginPreferencesPage(Gtk.ScrolledWindow): self.set_min_content_height(500) self.set_min_content_width(600) - wrapper_box.pack_start(self._infobar_revealer, expand=False, fill=False, padding=0) - wrapper_box.pack_start(plugins_box, expand=False, fill=False, padding=0) - wrapper_box.pack_start(note_label, expand=False, fill=False, padding=0) + wrapper_box.prepend(self._infobar_revealer) + wrapper_box.prepend(plugins_box) + wrapper_box.prepend(note_label) # Helpers self._infobar_timer = None diff --git a/pitivi/dialogs/projectsettings.py b/pitivi/dialogs/projectsettings.py index e8eaa6f76..68a5200e1 100644 --- a/pitivi/dialogs/projectsettings.py +++ b/pitivi/dialogs/projectsettings.py @@ -89,7 +89,9 @@ class ProjectSettingsDialog: # Add custom framerate fraction widget. frame_rate_box = self.builder.get_object("frame_rate_box") self.frame_rate_fraction_widget = FractionWidget() - frame_rate_box.pack_end(self.frame_rate_fraction_widget, True, True, 0) + self.frame_rate_fraction_widget.set_hexpand(True) + self.frame_rate_fraction_widget.set_halign(Gtk.Align.FILL) + frame_rate_box.append(self.frame_rate_fraction_widget) self.frame_rate_fraction_widget.show() # Behavior. diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index bc6831594..574f15eef 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -342,8 +342,8 @@ class EditorPerspective(Perspective, Loggable): undo_redo_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0) undo_redo_box.get_style_context().add_class("linked") - undo_redo_box.pack_start(undo_button, expand=False, fill=False, padding=0) - undo_redo_box.pack_start(redo_button, expand=False, fill=False, padding=0) + undo_redo_box.prepend(undo_button) + undo_redo_box.prepend(redo_button) headerbar.pack_start(undo_redo_box) self.builder.add_from_file( diff --git a/pitivi/effects.py b/pitivi/effects.py index d61ae68b1..1efbe8c1a 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -402,6 +402,8 @@ class EffectListWidget(Gtk.Box, Loggable): self.main_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.category_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.category_view.set_hexpand(True) + self.category_view.set_halign(Gtk.Align.FILL) # Used for showing search results and favourites self.search_view = Gtk.ListBox(activate_on_single_click=False) @@ -410,17 +412,21 @@ class EffectListWidget(Gtk.Box, Loggable): placeholder_text = Gtk.Label(_("No effects")) placeholder_text.props.visible = True self.search_view.set_placeholder(placeholder_text) + self.search_view.set_hexpand(True) + self.search_view.set_halign(Gtk.Align.FILL) - self.main_view.pack_start(self.category_view, True, True, 0) - self.main_view.pack_start(self.search_view, True, True, 0) + self.main_view.prepend(self.category_view) + self.main_view.prepend(self.search_view) scrollwin = Gtk.ScrolledWindow() scrollwin.props.hscrollbar_policy = Gtk.PolicyType.NEVER scrollwin.props.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC + scrollwin.set_vexpand(True) + scrollwin.set_valign(Gtk.Align.FILL) scrollwin.add(self.main_view) - self.pack_start(toolbar, False, False, 0) - self.pack_start(scrollwin, True, True, 0) + self.prepend(toolbar) + self.prepend(scrollwin) # Delay the loading of the available effects so the application # starts faster. @@ -484,25 +490,36 @@ class EffectListWidget(Gtk.Box, Loggable): effect_box.effect_name = effect_name effect_box.set_tooltip_text(effect_info.description) label = Gtk.Label(effect_info.human_name, xalign=0) + label.set_halign(Gtk.Align.FILL) + label.set_hexpand(True) if not only_text: # Show effect thumbnail icon = Gtk.Image.new_from_pixbuf(effect_info.icon) - effect_box.pack_start(icon, False, True, SPACING / 2) + icon.props.margin_top = SPACING / 2 + icon.props.margin_bottom = SPACING / 2 + icon.props.margin_start = SPACING / 2 + icon.props.margin_end = SPACING / 2 + icon.set_halign(Gtk.Align.FILL) + effect_box.prepend(icon) # Set up favourite button fav_button = Gtk.Button() fav_button.props.relief = Gtk.ReliefStyle.NONE fav_button.props.halign = Gtk.Align.CENTER fav_button.props.valign = Gtk.Align.CENTER + fav_button.set_margin_top(SPACING / 2) + fav_button.set_margin_bottom(SPACING / 2) + fav_button.set_margin_start(SPACING / 2) + fav_button.set_margin_end(SPACING / 2) fav_button.set_tooltip_text(_("Add to Favorites")) starred = effect_name in self.app.settings.favourite_effects self._set_fav_button_state(fav_button, starred) fav_button.connect("clicked", self._fav_button_clicked_cb, effect_box.effect_name) - effect_box.pack_end(fav_button, False, True, SPACING / 2) + effect_box.append(fav_button) - effect_box.pack_start(label, True, True, 0) + effect_box.prepend(label) # Set up drag behavoir eventbox = Gtk.EventBox(visible_window=False) @@ -670,6 +687,8 @@ class EffectsPopover(Gtk.Popover, Loggable): scroll_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scroll_window.props.max_content_height = 350 scroll_window.props.propagate_natural_height = True + scroll_window.set_vexpand(True) + scroll_window.set_valign(Gtk.Align.FILL) self.listbox = Gtk.ListBox() self.listbox.connect("row-activated", self._effect_row_activate_cb) @@ -681,8 +700,8 @@ class EffectsPopover(Gtk.Popover, Loggable): self.app.gui.editor.effectlist.add_effects_to_listbox(self.listbox, only_text=True) scroll_window.add(self.listbox) - vbox.pack_start(self.search_entry, False, False, 0) - vbox.pack_end(scroll_window, True, True, 0) + vbox.prepend(self.search_entry) + vbox.append(scroll_window) vbox.show_all() self.add(vbox) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index a575fb0be..47651a24b 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -202,7 +202,7 @@ class GreeterPerspective(Perspective): self.__topvbox.remove(current_child) if child: - self.__topvbox.pack_start(child, False, False, 0) + self.__topvbox.prepend(child) if recent_items: self.__search_entry.show() @@ -443,7 +443,7 @@ class GreeterPerspective(Perspective): label.props.halign = Gtk.Align.START label.props.wrap = True label.props.xalign = 0 - box.pack_start(label, False, False, 0) + box.prepend(label) grid = Gtk.Grid() grid.props.row_spacing = SPACING @@ -470,7 +470,7 @@ class GreeterPerspective(Perspective): description_label.props.yalign = Gtk.Align.START grid.attach(description_label, 2, row_index, 1, 1) - box.pack_start(grid, False, False, 0) + box.prepend(grid) wrapper_bin = BinWithNaturalWidth(box, width=500) wrapper_bin.show_all() diff --git a/pitivi/interactiveintro.py b/pitivi/interactiveintro.py index ef2a66085..31a85606e 100644 --- a/pitivi/interactiveintro.py +++ b/pitivi/interactiveintro.py @@ -114,12 +114,20 @@ class InteractiveIntro(GObject.Object): label.set_markup(text) label.set_line_wrap(True) label.set_max_width_chars(24) + label.props.margin_top = 5 + label.props.margin_bottom = 5 + label.props.margin_start = 5 + label.props.margin_end = 5 img = Gtk.Image.new_from_icon_name("dialog-information-symbolic", Gtk.IconSize.DIALOG) + img.props.margin_top = 5 + img.props.margin_bottom = 5 + img.props.margin_start = 5 + img.props.margin_end = 5 vbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - vbox.pack_start(img, False, False, 5) - vbox.pack_end(label, False, False, 5) + vbox.prepend(img) + vbox.prepend(label) vbox.show_all() popover.add(vbox) @@ -152,10 +160,15 @@ class InteractiveIntro(GObject.Object): def show_control_popover(self): # pylint: disable=attribute-defined-outside-init overview_button = Gtk.Button.new_with_label(_("Start Overview")) + overview_button.props.margin_top = 10 + overview_button.props.margin_bottom = 10 + overview_button.props.margin_start = 10 + overview_button.props.margin_end = 10 + overview_button.set_halign(Gtk.Align.FILL) overview_button.connect("clicked", self._overview_button_clicked_cb) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - vbox.pack_start(overview_button, False, True, 10) + vbox.prepend(overview_button) self.intro_button.show() self.intro_button.get_style_context().add_class("intro-highlight") diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index a7e831c20..27a1fefe8 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -120,17 +120,19 @@ class PreviewWidget(Gtk.Grid, Loggable): self.play_button = Gtk.ToolButton() self.play_button.set_icon_name("media-playback-start") self.play_button.connect("clicked", self._on_start_stop_clicked_cb) - self.bbox.pack_start(self.play_button, False, False, 0) + self.bbox.prepend(self.play_button) # Scale for position handling self.pos_adj = Gtk.Adjustment() self.seeker = Gtk.Scale.new(Gtk.Orientation.HORIZONTAL, self.pos_adj) + self.seeker.set_hexpand(True) + self.seeker.set_halign(Gtk.Align.FILL) self.seeker.connect('button-press-event', self._on_seeker_press_cb) self.seeker.connect('button-release-event', self._on_seeker_press_cb) self.seeker.connect('motion-notify-event', self._on_motion_notify_cb) self.seeker.set_draw_value(False) self.seeker.show() - self.bbox.pack_start(self.seeker, True, True, 0) + self.bbox.prepend(self.seeker) # Zoom buttons self.b_zoom_in = Gtk.ToolButton() @@ -139,8 +141,8 @@ class PreviewWidget(Gtk.Grid, Loggable): self.b_zoom_out = Gtk.ToolButton() self.b_zoom_out.set_icon_name("zoom-out") self.b_zoom_out.connect("clicked", self._on_zoom_clicked_cb, -1) - self.bbox.pack_start(self.b_zoom_in, False, False, 0) - self.bbox.pack_start(self.b_zoom_out, False, False, 0) + self.bbox.prepend(self.b_zoom_in) + self.bbox.prepend(self.b_zoom_out) self.bbox.show_all() self.attach(self.bbox, 0, 2, 1, 1) @@ -156,10 +158,12 @@ class PreviewWidget(Gtk.Grid, Loggable): vbox.set_orientation(Gtk.Orientation.VERTICAL) vbox.set_spacing(SPACING) self.l_error = Gtk.Label(label=_("Pitivi can not preview this file.")) + self.l_error.set_hexpand(True) + self.l_error.set_halign(Gtk.Align.FILL) self.b_details = Gtk.Button.new_with_label(_("More info")) self.b_details.connect('clicked', self._on_b_details_clicked_cb) - vbox.pack_start(self.l_error, True, True, 0) - vbox.pack_start(self.b_details, False, False, 0) + vbox.prepend(self.l_error) + vbox.prepend(self.b_details) vbox.show() self.attach(vbox, 0, 4, 1, 1) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index cc7a44e97..2ba42d223 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -147,7 +147,7 @@ class FileChooserExtraWidget(Gtk.Box, Loggable): self.__keep_open_check.props.valign = Gtk.Align.START self.__keep_open_check.set_tooltip_text(_("When importing files keep the dialog open")) self.__keep_open_check.set_active(not self.app.settings.closeImportDialog) - self.pack_start(self.__keep_open_check, expand=False, fill=False, padding=0) + self.prepend(self.__keep_open_check) self.hq_proxy_check = Gtk.CheckButton.new() # Translators: Create optimized media for unsupported files. @@ -158,11 +158,19 @@ class FileChooserExtraWidget(Gtk.Box, Loggable): self.hq_combo.insert_text(OptimizeOption.UNSUPPORTED_ASSETS, _("Unsupported assets")) self.hq_combo.insert_text(OptimizeOption.ALL, _("All")) self.hq_combo.props.active = OptimizeOption.UNSUPPORTED_ASSETS + self.hq_combo.props.margin_top = PADDING + self.hq_combo.props.margin_bottom = PADDING + self.hq_combo.props.margin_start = PADDING + self.hq_combo.props.margin_end = PADDING self.hq_combo.set_sensitive(False) self.help_button = Gtk.Button() self.__update_help_button() self.help_button.props.relief = Gtk.ReliefStyle.NONE + self.help_button.props.margin_top = SPACING + self.help_button.props.margin_bottom = SPACING + self.help_button.props.margin_start = SPACING + self.help_button.props.margin_end = SPACING self.help_button.connect("clicked", self._help_button_clicked_cb) self.scaled_proxy_check = Gtk.CheckButton.new() @@ -171,22 +179,30 @@ class FileChooserExtraWidget(Gtk.Box, Loggable): self.project_settings_label = Gtk.Label() self.project_settings_label.set_markup("%s" % _("Project Settings")) + self.project_settings_label.props.margin_top = SPACING + self.project_settings_label.props.margin_bottom = SPACING + self.project_settings_label.props.margin_start = SPACING + self.project_settings_label.props.margin_end = SPACING self.project_settings_label.connect("activate-link", self._target_res_cb) proxy_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + proxy_box.props.margin_top = SPACING * 2 + proxy_box.props.margin_bottom = SPACING * 2 + proxy_box.props.margin_start = SPACING * 2 + proxy_box.props.margin_end = SPACING * 2 hq_proxy_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - hq_proxy_row.pack_start(self.hq_proxy_check, expand=False, fill=False, padding=0) - hq_proxy_row.pack_start(self.hq_combo, expand=False, fill=False, padding=PADDING) - hq_proxy_row.pack_start(self.help_button, expand=False, fill=False, padding=SPACING) - proxy_box.pack_start(hq_proxy_row, expand=False, fill=False, padding=0) + hq_proxy_row.prepend(self.hq_proxy_check) + hq_proxy_row.prepend(self.hq_combo) + hq_proxy_row.prepend(self.help_button) + proxy_box.prepend(hq_proxy_row) row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - row.pack_start(self.scaled_proxy_check, expand=False, fill=False, padding=0) - row.pack_start(self.project_settings_label, expand=False, fill=False, padding=SPACING) - proxy_box.pack_start(row, expand=False, fill=False, padding=0) + row.prepend(self.scaled_proxy_check) + row.prepend(self.project_settings_label) + proxy_box.prepend(row) - self.pack_start(proxy_box, expand=False, fill=False, padding=SPACING * 2) + self.prepend(proxy_box) self.show_all() @@ -573,6 +589,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.tags_button = builder.get_object("tags_button") self.scrollwin = Gtk.ScrolledWindow() + self.scrollwin.set_halign(Gtk.Align.FILL) + self.scrollwin.set_hexpand(True) self.scrollwin.set_policy( Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scrollwin.get_accessible().set_name( @@ -643,13 +661,13 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.scrollwin.show_all() # Add all the child widgets. - self.pack_start(toolbar, False, False, 0) - self.pack_start(self._welcome_infobar, False, False, 0) - self.pack_start(self._project_settings_infobar, False, False, 0) - self.pack_start(self._import_warning_infobar, False, False, 0) - self.pack_start(self.scrollwin, True, True, 0) - self.pack_start(self._progressbar, False, False, 0) - self.pack_start(bottom_toolbar_container, False, False, 0) + self.prepend(toolbar) + self.prepend(self._welcome_infobar) + self.prepend(self._project_settings_infobar) + self.prepend(self._import_warning_infobar) + self.prepend(self.scrollwin) + self.prepend(self._progressbar) + self.prepend(bottom_toolbar_container) self.filter_store() @@ -660,7 +678,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): icon = Gtk.Image.new_from_pixbuf(item.icon_128) - box.pack_start(icon, False, False, 0) + box.prepend(icon) box.set_tooltip_markup(item.infotext) box.show_all() @@ -678,8 +696,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable): label.set_markup(item.infotext) label.set_yalign(0) - box.pack_start(icon, False, False, 0) - box.pack_start(label, False, False, 0) + box.prepend(icon) + box.prepend(label) box.show_all() return box @@ -1272,6 +1290,12 @@ class MediaLibraryWidget(Gtk.Box, Loggable): tags_list = Gtk.ListBox() tags_list.bind_model(tagstore, self.create_tagslist_widget_func) tags_list.set_can_focus(False) + tags_list.set_hexpand(True) + tags_list.set_halign(Gtk.Align.FILL) + tags_list.set_margin_top(PADDING) + tags_list.set_margin_bottom(PADDING) + tags_list.set_margin_start(PADDING) + tags_list.set_margin_end(PADDING) new_entry_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.new_tag_entry = Gtk.Entry() @@ -1279,15 +1303,23 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.new_tag_entry.set_width_chars(12) self.new_tag_entry.connect("activate", self.new_tag_entry_activated_cb, tagstore) add_tag_button = Gtk.Button.new_with_label(_("Add")) + add_tag_button.props.margin_top = PADDING + add_tag_button.props.margin_bottom = PADDING + add_tag_button.props.margin_start = PADDING + add_tag_button.props.margin_end = PADDING add_tag_button.connect("clicked", self.add_tag_button_clicked_cb, tagstore) - new_entry_box.pack_start(self.new_tag_entry, False, False, 0) - new_entry_box.pack_start(add_tag_button, False, False, PADDING) + new_entry_box.prepend(self.new_tag_entry) + new_entry_box.prepend(add_tag_button) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.props.margin = PADDING - box.pack_start(popover_heading, False, False, SPACING) - box.pack_start(tags_list, True, True, PADDING) - box.pack_start(new_entry_box, False, False, 0) + popover_heading.props.margin_top = SPACING + popover_heading.props.margin_bottom = SPACING + popover_heading.props.margin_start = SPACING + popover_heading.props.margin_end = SPACING + box.append(popover_heading) + box.prepend(tags_list) + box.prepend(new_entry_box) self.tags_popover.connect("closed", self._tags_popover_closed_cb, tags_list, tagstore) self.tags_popover.add(box) diff --git a/pitivi/project.py b/pitivi/project.py index 9e2a8eeca..d9202e167 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -205,6 +205,8 @@ class ProjectManager(GObject.Object, Loggable): primary.set_use_markup(True) primary.set_alignment(0, 0.5) primary.props.label = message + primary.set_hexpand(True) + primary.set_halign(Gtk.Align.FILL) # These 2 lines are needed for a decent dialog width, with wrapped text: dialog.props.default_width = 700 @@ -212,21 +214,26 @@ class ProjectManager(GObject.Object, Loggable): # put the text in a vbox vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=SPACING * 2) - vbox.pack_start(primary, True, True, 0) + vbox.set_hexpand(True) + vbox.set_valign(Gtk.Align.FILL) + vbox.prepend(primary) # make the [[image] text] hbox image = Gtk.Image.new_from_icon_name("dialog-error-symbolic", Gtk.IconSize.DIALOG) + image.set_halign(Gtk.Align.FILL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=SPACING * 2) - hbox.pack_start(image, False, True, 0) - hbox.pack_start(vbox, True, True, 0) + hbox.prepend(image) + hbox.prepend(vbox) hbox.set_margin_top(SPACING) hbox.set_margin_bottom(SPACING) hbox.set_margin_start(SPACING) hbox.set_margin_end(SPACING) + hbox.set_hexpand(True) + hbox.set_halign(Gtk.Align.FILL) # stuff the hbox in the dialog content_area = dialog.get_content_area() - content_area.pack_start(hbox, True, True, 0) + content_area.prepend(hbox) content_area.set_spacing(SPACING * 2) hbox.show_all() @@ -306,27 +313,33 @@ class ProjectManager(GObject.Object, Loggable): "Would you like to load it instead?") % \ beautify_time_delta(time_diff) primary.props.label = message + primary.set_hexpand(True) + primary.set_halign(Gtk.Align.FILL) # put the text in a vbox vbox = Gtk.Box(homogeneous=False, spacing=SPACING * 2) vbox.set_orientation(Gtk.Orientation.VERTICAL) - vbox.pack_start(primary, True, True, 0) + vbox.set_vexpand(True) + vbox.set_valign(Gtk.Align.FILL) + vbox.prepend(primary) # make the [[image] text] hbox image = Gtk.Image.new_from_icon_name( "dialog-question-symbolic", Gtk.IconSize.DIALOG) hbox = Gtk.Box(homogeneous=False, spacing=SPACING * 2) hbox.set_orientation(Gtk.Orientation.HORIZONTAL) - hbox.pack_start(image, False, False, 0) - hbox.pack_start(vbox, True, True, 0) + hbox.prepend(image) + hbox.prepend(vbox) hbox.set_margin_top(SPACING) hbox.set_margin_bottom(SPACING) hbox.set_margin_start(SPACING) hbox.set_margin_end(SPACING) + hbox.set_hexpand(True) + hbox.set_halign(Gtk.Align.FILL) # stuff the hbox in the dialog content_area = dialog.get_content_area() - content_area.pack_start(hbox, True, True, 0) + content_area.prepend(hbox) content_area.set_spacing(SPACING * 2) hbox.show_all() diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 56c072116..9811bd5fb 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -1583,10 +1583,11 @@ class FullSourceClip(SourceClip, FullClip): return ges_source.ui = widget + widget.set_hexpand(True) if ges_source.get_track_type() == GES.TrackType.VIDEO: - self._elements_container.pack_start(widget, expand=True, fill=False, padding=0) + self._elements_container.prepend(widget) else: - self._elements_container.pack_end(widget, expand=True, fill=False, padding=0) + self._elements_container.append(widget) widget.set_visible(True) def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: @@ -1609,7 +1610,8 @@ class MiniSourceClip(SourceClip, MiniClip): return ges_source.mini_ui = widget - self._elements_container.pack_start(widget, expand=True, fill=False, padding=0) + self._elements_container.prepend(widget) + widget.set_hexpand(True) widget.set_visible(True) def _create_child_widget(self, ges_source: GES.Source) -> Optional[Gtk.Widget]: diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 91fe362ba..118c292b4 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -78,17 +78,19 @@ class LayerControls(Gtk.EventBox, Loggable): self.add(hbox) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - hbox.pack_start(vbox, True, True, 0) + vbox.set_vexpand(True) + vbox.set_valign(Gtk.Align.FILL) + hbox.prepend(vbox) rightside_separator = Gtk.Separator.new(Gtk.Orientation.VERTICAL) - hbox.pack_start(rightside_separator, False, False, 0) + hbox.prepend(rightside_separator) name_row = Gtk.Box() name_row.set_orientation(Gtk.Orientation.HORIZONTAL) name_row.props.margin_top = PADDING name_row.props.margin_start = PADDING name_row.props.margin_end = PADDING - vbox.pack_start(name_row, False, False, 0) + vbox.prepend(name_row) self.menubutton = Gtk.MenuButton.new() self.menubutton.props.valign = Gtk.Align.CENTER @@ -98,15 +100,17 @@ class LayerControls(Gtk.EventBox, Loggable): popover.insert_action_group("layer", action_group) popover.props.position = Gtk.PositionType.LEFT self.menubutton.set_popover(popover) - name_row.pack_start(self.menubutton, False, False, 0) + name_row.prepend(self.menubutton) self.name_entry = Gtk.Entry() self.name_entry.get_style_context().add_class("LayerControlEntry") self.name_entry.props.valign = Gtk.Align.CENTER + self.name_entry.set_hexpand(True) + self.name_entry.set_halign(Gtk.Align.FILL) self.name_entry.connect("focus-out-event", self.__name_focus_out_cb) self.ges_layer.connect("notify-meta", self.__layer_rename_cb) self.__update_name() - name_row.pack_start(self.name_entry, True, True, 0) + name_row.prepend(self.name_entry) self.audio_button = Gtk.Button.new() self.audio_button.connect("clicked", self.__audio_button_clicked_cb) @@ -120,11 +124,11 @@ class LayerControls(Gtk.EventBox, Loggable): control_box.add(self.video_button) control_box.add(self.audio_button) control_box.get_style_context().add_class("linked") - name_row.pack_start(control_box, False, False, 0) + name_row.prepend(control_box) space = Gtk.Label() space.props.vexpand = True - vbox.pack_start(space, False, False, 0) + vbox.prepend(space) self.ges_layer.connect("notify::priority", self.__layer_priority_changed_cb) self.ges_layer.connect("active-changed", self.__layer_active_changed_cb) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index f19e3de53..5ad599a34 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -390,9 +390,11 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.layout = FullLayersLayout(self) self.layout.props.can_focus = True self.layout.props.can_default = True + self.layout.set_hexpand(True) + self.layout.set_halign(Gtk.Align.FILL) self.hadj = self.layout.get_hadjustment() self.vadj = self.layout.get_vadjustment() - hbox.pack_end(self.layout, True, True, 0) + hbox.append(self.layout) self.mini_layout = MiniLayersLayout(self) @@ -414,14 +416,14 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): scrolled_window.props.propagate_natural_width = True scrolled_window.props.vscrollbar_policy = Gtk.PolicyType.EXTERNAL scrolled_window.add(self._layers_controls_vbox) - hbox.pack_start(scrolled_window, False, False, 0) + hbox.prepend(scrolled_window) self.add_layer_button = Gtk.Button.new_with_label(_("Add layer")) self.add_layer_button.props.margin = SPACING self.add_layer_button.set_halign(Gtk.Align.CENTER) self.add_layer_button.show() self.add_layer_button.set_action_name("timeline.add-layer") - self._layers_controls_vbox.pack_end(self.add_layer_button, False, False, 0) + self._layers_controls_vbox.append(self.add_layer_button) self.get_style_context().add_class("Timeline") self.props.expand = True @@ -1272,16 +1274,16 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): control = LayerControls(ges_layer, self.app) control.show_all() - self._layers_controls_vbox.pack_start(control, False, False, 0) + self._layers_controls_vbox.prepend(control) ges_layer.control_ui = control # Check the media types so the controls are set up properly. layer.check_media_types() mini_layer.check_media_types() - self.layout.layers_vbox.pack_start(layer, False, False, 0) + self.layout.layers_vbox.prepend(layer) layer.show() - self.mini_layout.layers_vbox.pack_start(mini_layer, False, False, 0) + self.mini_layout.layers_vbox.prepend(mini_layer) mini_layer.show() self.__add_separators() @@ -1292,15 +1294,15 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): """Adds separators to separate layers.""" controls_separator = SpacedSeparator() controls_separator.show() - self._layers_controls_vbox.pack_start(controls_separator, False, False, 0) + self._layers_controls_vbox.prepend(controls_separator) separator = SpacedSeparator() separator.show() - self.layout.layers_vbox.pack_start(separator, False, False, 0) + self.layout.layers_vbox.prepend(separator) mini_separator = SpacedSeparator() mini_separator.show() - self.mini_layout.layers_vbox.pack_start(mini_separator, False, False, 0) + self.mini_layout.layers_vbox.prepend(mini_separator) self._separators.append((controls_separator, separator, mini_separator)) diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index 7f44abedc..1cb2a2ef7 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -285,7 +285,7 @@ class ToplevelWidget(Gtk.Box, Loggable): # Setup algorithm ComboBox cell = Gtk.CellRendererText() self.algorithm_combo_box.set_model(self.__get_tracking_algorithms()) - self.algorithm_combo_box.pack_start(cell, False) + self.algorithm_combo_box.prepend(cell) self.algorithm_combo_box.add_attribute(cell, "text", 0) self._setup(None) @@ -708,9 +708,11 @@ class CoverObjectPopover(Gtk.Popover, Loggable): self.scroll_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scroll_window.props.max_content_height = 350 self.scroll_window.props.propagate_natural_height = True + self.scroll_window.set_hexpand(True) + self.scroll_window.set_halign(Gtk.Align.FILL) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, margin=PADDING) - vbox.pack_start(self.scroll_window, True, True, 0) + vbox.prepend(self.scroll_window) vbox.show_all() self.add(vbox) diff --git a/pitivi/transitions.py b/pitivi/transitions.py index 8ad76ae82..ffa751bfa 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -70,7 +70,9 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.search_entry.set_icon_from_icon_name( Gtk.EntryIconPosition.SECONDARY, "edit-clear-symbolic") self.search_entry.set_placeholder_text(_("Search...")) - self.searchbar.pack_end(self.search_entry, True, True, 0) + self.search_entry.set_hexpand(True) + self.search_entry.set_halign(Gtk.Align.FILL) + self.searchbar.append(self.search_entry) self.props_widgets = Gtk.Grid() self.props_widgets.props.margin = PADDING @@ -113,11 +115,13 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.iconview_scrollwin = Gtk.ScrolledWindow() self.iconview_scrollwin.set_shadow_type(Gtk.ShadowType.ETCHED_IN) + self.iconview_scrollwin.set_hexpand(True) + self.iconview_scrollwin.set_halign(Gtk.Align.FILL) self.iconview = Gtk.IconView(model=self.model_filter) cell_renderer = Gtk.CellRendererPixbuf() cell_renderer.props.stock_size = Gtk.IconSize.DIALOG - self.iconview.pack_start(cell_renderer, expand=False) + self.iconview.prepend(cell_renderer) self.iconview.add_attribute(cell_renderer, "icon-name", COL_ICON_NAME) self.iconview.set_item_width(48 + SPACING) @@ -132,10 +136,10 @@ class TransitionsListWidget(Gtk.Box, Loggable): # Speed-up startup by only checking available transitions on idle GLib.idle_add(self._load_available_transitions_cb) - self.pack_start(self.infobar, False, False, 0) - self.pack_start(self.searchbar, False, False, 0) - self.pack_start(self.iconview_scrollwin, True, True, 0) - self.pack_start(self.props_widgets, False, False, 0) + self.prepend(self.infobar) + self.prepend(self.searchbar) + self.prepend(self.iconview_scrollwin) + self.prepend(self.props_widgets) self.infobar.show_all() self.iconview_scrollwin.show_all() diff --git a/pitivi/utils/custom_effect_widgets.py b/pitivi/utils/custom_effect_widgets.py index 5c2e27157..86f526895 100644 --- a/pitivi/utils/custom_effect_widgets.py +++ b/pitivi/utils/custom_effect_widgets.py @@ -424,7 +424,7 @@ def create_alphaspot_widget(effect_prop_manager, element_setting_widget, element ]) shape_picker.set_model(shape_list) shape_text_renderer = Gtk.CellRendererText() - shape_picker.pack_start(shape_text_renderer, 0) + shape_picker.prepend(shape_text_renderer) shape_picker.add_attribute(shape_text_renderer, "text", 0) def get_current_shape(): @@ -465,7 +465,7 @@ def create_alphaspot_widget(effect_prop_manager, element_setting_widget, element ]) op_picker.set_model(op_list) op_text_renderer = Gtk.CellRendererText() - op_picker.pack_start(op_text_renderer, 0) + op_picker.prepend(op_text_renderer) op_picker.add_attribute(op_text_renderer, "text", 0) def get_current_op(): diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 523d45292..818423864 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -120,18 +120,18 @@ class TextWidget(Gtk.Box, DynamicWidget): self.combo = Gtk.ComboBoxText.new_with_entry() self.text = self.combo.get_child() self.combo.show() - self.pack_start(self.combo, expand=False, fill=False, padding=0) + self.prepend(self.combo) for choice in choices: self.combo.append_text(choice) elif combobox: self.combo = Gtk.ComboBox.new_with_entry() self.text = self.combo.get_child() self.combo.show() - self.pack_start(self.combo, expand=False, fill=False, padding=0) + self.prepend(self.combo) else: self.text = Gtk.Entry() self.text.show() - self.pack_start(self.text, expand=False, fill=False, padding=0) + self.prepend(self.text) else: self.text = widget @@ -237,13 +237,13 @@ class NumericWidget(Gtk.Box, DynamicWidget): self.spinner = Gtk.SpinButton(adjustment=self.adjustment) if width_chars: self.spinner.props.width_chars = width_chars - self.pack_start(self.spinner, expand=False, fill=False, padding=0) + self.prepend(self.spinner) self.spinner.show() if with_slider: self.slider = Gtk.Scale.new( Gtk.Orientation.HORIZONTAL, self.adjustment) - self.pack_start(self.slider, expand=False, fill=False, padding=0) + self.prepend(self.slider) self.slider.show() self.slider.set_size_request(width=100, height=-1) self.slider.props.draw_value = False @@ -447,7 +447,7 @@ class ToggleWidget(Gtk.Box, DynamicWidget): self.props.valign = Gtk.Align.CENTER if switch_button is None: self.switch_button = Gtk.Switch() - self.pack_start(self.switch_button, expand=False, fill=False, padding=0) + self.prepend(self.switch_button) self.switch_button.show() else: self.switch_button = switch_button @@ -476,7 +476,7 @@ class ChoiceWidget(Gtk.Box, DynamicWidget): self.values = None self.set_orientation(Gtk.Orientation.HORIZONTAL) self.contents = Gtk.ComboBoxText() - self.pack_start(self.contents, expand=False, fill=False, padding=0) + self.prepend(self.contents) self.set_choices(choices) self.contents.show() cell = self.contents.get_cells()[0] @@ -594,10 +594,14 @@ class InputValidationWidget(Gtk.Box, DynamicWidget): self._widget = widget self._validation_function = validation_function self._warning_sign = Gtk.Image.new_from_icon_name("dialog-warning-symbolic", Gtk.IconSize.LARGE_TOOLBAR) + self._warning_sign.props.margin_top = SPACING + self._warning_sign.props.margin_bottom = SPACING + self._warning_sign.props.margin_start = SPACING + self._warning_sign.props.margin_end = SPACING self.set_orientation(Gtk.Orientation.HORIZONTAL) - self.pack_start(self._widget, expand=False, fill=False, padding=0) - self.pack_start(self._warning_sign, expand=False, fill=False, padding=SPACING) + self.prepend(self._widget) + self.prepend(self._warning_sign) self._warning_sign.set_no_show_all(True) self._widget.connect_value_changed(self._widget_value_changed_cb) @@ -695,7 +699,9 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): break def show_widget(self, widget): - self.pack_start(widget, True, True, 0) + widget.set_hexpand(True) + widget.set_halign(Gtk.Align.FILL) + self.prepend(widget) disable_scroll(widget) self.show_all() @@ -833,7 +839,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): if prop.name not in self.ignore] if not props: widget = Gtk.Label(label=_("No properties.")) - self.pack_start(widget, expand=False, fill=False, padding=0) + self.prepend(widget) widget.show() return @@ -930,7 +936,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): grid.attach(button, 3, y, 1, 1) self.element.connect('deep-notify', self._property_changed_cb) - self.pack_start(grid, expand=False, fill=False, padding=0) + self.prepend(grid) self.show_all() def _make_widget_from_gvalue(self, gvalue, default): diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 0ea7a183e..de989de37 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -139,7 +139,7 @@ class ViewerContainer(Gtk.Box, Loggable): new_peak_meter.set_margin_bottom(SPACING) new_peak_meter.set_margin_top(SPACING) self.peak_meters.append(new_peak_meter) - self.peak_meter_box.pack_start(self.peak_meters[i], False, False, 0) + self.peak_meter_box.prepend(self.peak_meters[i]) self.peak_meter_box.show_all() @@ -183,13 +183,18 @@ class ViewerContainer(Gtk.Box, Loggable): sink_widget, self.guidelines_popover.overlay) self.target = ViewerWidget(self.overlay_stack) + self.target.set_hexpand(True) + self.target.set_halign(Gtk.Align.FILL) self._reset_viewer_aspect_ratio(self.project) - self.viewer_row_box.pack_start(self.target, expand=True, fill=True, padding=0) + self.viewer_row_box.prepend(self.target) if self.docked: - self.pack_start(self.viewer_row_box, expand=True, fill=True, padding=0) + self.viewer_row_box.set_hexpand(True) + self.viewer_row_box.set_halign(Gtk.Align.FILL) + self.prepend(self.viewer_row_box) else: - self.external_vbox.pack_start(self.viewer_row_box, expand=True, fill=False, padding=0) + self.viewer_row_box.set_hexpand(True) + self.external_vbox.prepend(self.viewer_row_box) self.external_vbox.child_set(self.viewer_row_box, fill=True) self.viewer_row_box.show_all() @@ -268,7 +273,7 @@ class ViewerContainer(Gtk.Box, Loggable): corner.connect("button-press-event", self.__corner_button_press_cb, hpane, vpane) corner.connect("button-release-event", self.__corner_button_release_cb) corner.connect("motion-notify-event", self.__corner_motion_notify_cb, hpane, vpane) - self.pack_end(corner, False, False, 0) + self.append(corner) # Peak Meters self.peak_meter_box = Gtk.Box() @@ -285,8 +290,8 @@ class ViewerContainer(Gtk.Box, Loggable): self.peak_meter_scale.set_property("valign", Gtk.Align.FILL) self.peak_meter_scale.set_property("halign", Gtk.Align.CENTER) self.peak_meter_scale.set_margin_start(SPACING) - self.peak_meter_box.pack_end(self.peak_meter_scale, False, False, 0) - self.viewer_row_box.pack_end(self.peak_meter_box, False, False, 0) + self.peak_meter_box.append(self.peak_meter_scale) + self.viewer_row_box.append(self.peak_meter_box) self.peak_meter_scale.connect("configure-event", self.__peak_meter_scale_configure_event_cb) # Buttons/Controls @@ -296,13 +301,13 @@ class ViewerContainer(Gtk.Box, Loggable): bbox.set_property("halign", Gtk.Align.CENTER) bbox.set_margin_start(SPACING) bbox.set_margin_end(SPACING) - self.pack_end(bbox, False, False, 0) + self.append(bbox) self.guidelines_button = Gtk.MenuButton.new() self.guidelines_button.props.image = Gtk.Image.new_from_icon_name("view-grid-symbolic", Gtk.IconSize.BUTTON) self.guidelines_button.set_relief(Gtk.ReliefStyle.NONE) self.guidelines_button.set_tooltip_text(_("Select composition guidelines")) - bbox.pack_start(self.guidelines_button, False, False, 0) + bbox.prepend(self.guidelines_button) self.start_button = Gtk.Button.new_from_icon_name("media-skip-backward-symbolic", Gtk.IconSize.BUTTON) @@ -311,7 +316,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.start_button.set_tooltip_text( _("Go to the beginning of the timeline")) self.start_button.set_sensitive(False) - bbox.pack_start(self.start_button, False, False, 0) + bbox.prepend(self.start_button) self.back_button = Gtk.Button.new_from_icon_name("media-seek-backward-symbolic", Gtk.IconSize.BUTTON) @@ -320,11 +325,11 @@ class ViewerContainer(Gtk.Box, Loggable): self.back_button.connect("clicked", self._back_cb) self.back_button.set_tooltip_text(_("Go back one second")) self.back_button.set_sensitive(False) - bbox.pack_start(self.back_button, False, False, 0) + bbox.prepend(self.back_button) self.playpause_button = PlayPauseButton() self.playpause_button.connect("play", self._play_button_cb) - bbox.pack_start(self.playpause_button, False, False, 0) + bbox.prepend(self.playpause_button) self.playpause_button.set_sensitive(False) self.forward_button = Gtk.Button.new_from_icon_name("media-seek-forward-symbolic", @@ -333,7 +338,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.forward_button.connect("clicked", self._forward_cb) self.forward_button.set_tooltip_text(_("Go forward one second")) self.forward_button.set_sensitive(False) - bbox.pack_start(self.forward_button, False, False, 0) + bbox.prepend(self.forward_button) self.end_button = Gtk.Button.new_from_icon_name("media-skip-forward-symbolic", Gtk.IconSize.BUTTON) @@ -342,15 +347,19 @@ class ViewerContainer(Gtk.Box, Loggable): self.end_button.set_tooltip_text( _("Go to the end of the timeline")) self.end_button.set_sensitive(False) - bbox.pack_start(self.end_button, False, False, 0) + bbox.prepend(self.end_button) self.timecode_entry = TimeWidget() self.timecode_entry.set_widget_value(0) self.timecode_entry.set_tooltip_text( _('Enter a timecode or frame number\nand press "Enter" to go to that position')) + self.timecode_entry.props.margin_top = 15 + self.timecode_entry.props.margin_bottom = 15 + self.timecode_entry.props.margin_start = 15 + self.timecode_entry.props.margin_end = 15 self.timecode_entry.connect_activate_event(self._entry_activate_cb) self.timecode_entry.connect("key_press_event", self._entry_key_press_event_cb) - bbox.pack_start(self.timecode_entry, False, False, 15) + bbox.prepend(self.timecode_entry) self.undock_button = Gtk.Button.new_from_icon_name("view-restore-symbolic", Gtk.IconSize.BUTTON) @@ -359,7 +368,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.undock_button.connect("clicked", self.undock_cb) self.undock_button.set_tooltip_text( _("Detach the viewer\nYou can re-attach it by closing the newly created window.")) - bbox.pack_start(self.undock_button, False, False, 0) + bbox.prepend(self.undock_button) self.show_all() @@ -367,7 +376,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.hidden_chest = Gtk.Frame() # It has to be added to the window, otherwise when we add # a video widget to it, it will create a new window! - self.pack_end(self.hidden_chest, False, False, 0) + self.append(self.hidden_chest) # Identify widgets for AT-SPI, making our test suite easier to develop # These will show up in sniff, accerciser, etc. @@ -535,7 +544,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.viewer_row_box.remove(self.target) self.__create_new_viewer() self.buttons_container.set_margin_bottom(SPACING) - self.external_vbox.pack_end(self.buttons_container, False, False, 0) + self.external_vbox.append(self.buttons_container) self.undock_button.hide() self.fullscreen_button = Gtk.ToggleButton() @@ -545,8 +554,11 @@ class ViewerContainer(Gtk.Box, Loggable): self.fullscreen_button.set_tooltip_text( _("Show this window in fullscreen")) self.fullscreen_button.set_relief(Gtk.ReliefStyle.NONE) - self.buttons_container.pack_end( - self.fullscreen_button, expand=False, fill=False, padding=6) + self.fullscreen_button.set_margin_top(6) + self.fullscreen_button.set_margin_bottom(6) + self.fullscreen_button.set_margin_start(6) + self.fullscreen_button.set_margin_end(6) + self.buttons_container.append(self.fullscreen_button) self.fullscreen_button.show() self.fullscreen_button.connect("toggled", self._toggle_fullscreen_cb) @@ -584,7 +596,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.fullscreen_button.destroy() self.external_vbox.remove(self.buttons_container) self.buttons_container.set_margin_bottom(0) - self.pack_end(self.buttons_container, False, False, 0) + self.append(self.buttons_container) self.show() self.external_window.hide() -- GitLab From 536936b555cab4626b47c25e76095a638d69ed62 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Tue, 12 Jul 2022 13:43:32 +0530 Subject: [PATCH 012/132] Adapt to new cursor API --- pitivi/timeline/elements.py | 4 ++-- pitivi/timeline/layer.py | 2 +- pitivi/trackerperspective.py | 4 ++-- pitivi/utils/ui.py | 8 ++++---- pitivi/utils/widgets.py | 3 ++- pitivi/viewer/overlay_stack.py | 2 +- pitivi/viewer/viewer.py | 4 ++-- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 9811bd5fb..0dfe23382 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -285,7 +285,7 @@ class KeyframeCurve(FigureCanvasGTK3Cairo, Loggable): def _event_cb(self, unused_element, event): if event.type == Gdk.EventType.LEAVE_NOTIFY: cursor = NORMAL_CURSOR - self._timeline.get_window().set_cursor(cursor) + self._timeline.set_cursor(cursor) return False def _mpl_button_press_event_cb(self, event): @@ -378,7 +378,7 @@ class KeyframeCurve(FigureCanvasGTK3Cairo, Loggable): self._update_tooltip(None) self.__hovered = False - self._timeline.get_window().set_cursor(cursor) + self._timeline.set_cursor(cursor) def _mpl_button_release_event_cb(self, event): if event.button != MouseButton.LEFT: diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 118c292b4..dfb19c437 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -140,7 +140,7 @@ class LayerControls(Gtk.EventBox, Loggable): self.connect("notify::window", self.__window_set_cb) def __window_set_cb(self, unused_window, unused_pspec): - self.props.window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.HAND1)) + self.props.window.set_cursor(Gdk.Cursor.new_from_name("pointer")) def __del__(self): self.name_entry.disconnect_by_func(self.__name_focus_out_cb) diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index 1cb2a2ef7..c0c28b02b 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -417,11 +417,11 @@ class ToplevelWidget(Gtk.Box, Loggable): @Gtk.Template.Callback() def _drawing_area_enter_notify_event_cb(self, widget, event): - self.app.gui.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.CROSSHAIR)) + self.app.gui.set_cursor("crosshair") @Gtk.Template.Callback() def _drawing_area_leave_notify_event_cb(self, widget, event): - self.app.gui.get_window().set_cursor(NORMAL_CURSOR) + self.app.gui.set_cursor(NORMAL_CURSOR) @Gtk.Template.Callback() def _drawing_area_motion_notify_event_cb(self, widget, event): diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index 61d2ab62e..0e22e3b2d 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -77,12 +77,12 @@ TOUCH_INPUT_SOURCES = (Gdk.InputSource.TOUCHPAD, Gdk.InputSource.TABLET_PAD) CURSORS = { - GES.Edge.EDGE_START: Gdk.Cursor.new(Gdk.CursorType.LEFT_SIDE), - GES.Edge.EDGE_END: Gdk.Cursor.new(Gdk.CursorType.RIGHT_SIDE) + GES.Edge.EDGE_START: Gdk.Cursor.new_from_name("w-resize"), + GES.Edge.EDGE_END: Gdk.Cursor.new_from_name("e-resize") } -NORMAL_CURSOR = Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR) -DRAG_CURSOR = Gdk.Cursor.new(Gdk.CursorType.HAND1) +NORMAL_CURSOR = Gdk.Cursor.new_from_name("default") +DRAG_CURSOR = Gdk.Cursor.new_from_name("pointer") def get_month_format_string(): diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 818423864..2ccaa449d 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -1435,7 +1435,8 @@ class ColorPickerButton(Gtk.Button): except TypeError: pixbuf = GdkPixbuf.Pixbuf.new_from_data(DROPPER_BITS, GdkPixbuf.Colorspace.RGB, True, 8, DROPPER_WIDTH, DROPPER_HEIGHT, DROPPER_WIDTH * 4) - cursor = Gdk.Cursor.new_from_pixbuf(screen.get_display(), pixbuf, DROPPER_X_HOT, DROPPER_Y_HOT) + texture = Gdk.Texture.new_for_pixbuf(pixbuf) + cursor = Gdk.Cursor.new_from_texture(texture, DROPPER_X_HOT, DROPPER_Y_HOT) return cursor def button_release_event_cb(self, widget, event): diff --git a/pitivi/viewer/overlay_stack.py b/pitivi/viewer/overlay_stack.py index 9b2f4c695..f0e7ee64a 100644 --- a/pitivi/viewer/overlay_stack.py +++ b/pitivi/viewer/overlay_stack.py @@ -194,7 +194,7 @@ class OverlayStack(Gtk.Overlay, Loggable): self.app.gui.get_window().set_cursor(cursor) def reset_cursor(self): - self.app.gui.get_window().set_cursor(None) + self.app.gui.set_cursor(None) def get_drag_distance(self, cursor_position): return cursor_position - self.click_position diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index de989de37..ee57fdfa8 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -441,8 +441,8 @@ class ViewerContainer(Gtk.Box, Loggable): def __corner_enter_notify_cb(self, widget, unused_event): if not self.__cursor: - self.__cursor = Gdk.Cursor.new(Gdk.CursorType.BOTTOM_LEFT_CORNER) - widget.get_window().set_cursor(self.__cursor) + self.__cursor = Gdk.Cursor.new_from_name("sw-resize") + widget.set_cursor(self.__cursor) def __corner_button_press_cb(self, unused_widget, event, hpane, vpane): if event.button == 1: -- GitLab From ced56349c70d5ddd89d2c03dbcc8d4fe965b328c Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 13 Jul 2022 00:34:59 +0530 Subject: [PATCH 013/132] Remove deprecated GtkBin --- pitivi/utils/ui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index 0e22e3b2d..8e385d902 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -771,11 +771,11 @@ def beautify_last_updated_timestamp(last_updated_timestamp): # -------------------- Gtk widget helpers ----------------------------------- # -class BinWithNaturalWidth(Gtk.Bin): +class BinWithNaturalWidth(Gtk.Widget): """A bin with a maximum width.""" def __init__(self, child, width, *args, **kwargs): - Gtk.Bin.__init__(self, *args, **kwargs) + Gtk.Widget.__init__(self, *args, **kwargs) self.natural_width = width self.add(child) @@ -783,7 +783,7 @@ class BinWithNaturalWidth(Gtk.Bin): return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH def do_get_preferred_width(self): - minimum, _ = Gtk.Bin.do_get_preferred_width(self) + minimum, _ = Gtk.Widget.do_get_preferred_width(self) minimum = min(minimum, self.natural_width) return minimum, self.natural_width -- GitLab From 4ec3fec056f77e682d7461c6437bbf955dc01967 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 13 Jul 2022 00:53:05 +0530 Subject: [PATCH 014/132] Replace deprecated FileChooserButton --- pitivi/utils/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 2ccaa449d..6ce1d04f5 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -507,7 +507,7 @@ class ChoiceWidget(Gtk.Box, DynamicWidget): self.contents.set_sensitive(True) -class PathWidget(Gtk.FileChooserButton, DynamicWidget): +class PathWidget(Gtk.Button, DynamicWidget): """Widget for entering a path.""" __gtype_name__ = 'PathWidget' @@ -522,7 +522,7 @@ class PathWidget(Gtk.FileChooserButton, DynamicWidget): self.dialog.add_buttons( _("Cancel"), Gtk.ResponseType.CANCEL, _("Close"), Gtk.ResponseType.CLOSE) self.dialog.set_default_response(Gtk.ResponseType.OK) - Gtk.FileChooserButton.__init__(self, dialog=self.dialog) + Gtk.Button.__init__(self, dialog=self.dialog) self.dialog.connect("response", self._response_cb) self.uri = "" -- GitLab From d2018b1dae5aa0a14ddb2960030acf3dbbaad465 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 13 Jul 2022 01:02:52 +0530 Subject: [PATCH 015/132] Replace deprecated GtkEventBox --- pitivi/clip_properties/alignment.py | 4 ++-- pitivi/clipproperties.py | 2 +- pitivi/effects.py | 2 +- pitivi/timeline/elements.py | 12 ++++++------ pitivi/timeline/layer.py | 10 +++++----- pitivi/timeline/markers.py | 8 ++++---- pitivi/timeline/timeline.py | 9 +++------ 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pitivi/clip_properties/alignment.py b/pitivi/clip_properties/alignment.py index b890c2ab0..6cbe60114 100644 --- a/pitivi/clip_properties/alignment.py +++ b/pitivi/clip_properties/alignment.py @@ -23,7 +23,7 @@ from gi.repository import Gtk from pitivi.utils.loggable import Loggable -class AlignmentEditor(Gtk.EventBox, Loggable): +class AlignmentEditor(Gtk.Box, Loggable): """Widget for aligning a video clip. Attributes: @@ -38,7 +38,7 @@ class AlignmentEditor(Gtk.EventBox, Loggable): } def __init__(self): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Loggable.__init__(self) self._hovered_box = None diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index f5f7b4050..8b51336f9 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -718,7 +718,7 @@ class EffectProperties(Gtk.Expander, Loggable): vbox.prepend(row_widgets_box) vbox.prepend(config_ui_revealer) - event_box = Gtk.EventBox() + event_box = Gtk.Box() event_box.add(vbox) row = Gtk.ListBoxRow(selectable=False, activatable=False) diff --git a/pitivi/effects.py b/pitivi/effects.py index 1efbe8c1a..8a437a668 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -522,7 +522,7 @@ class EffectListWidget(Gtk.Box, Loggable): effect_box.prepend(label) # Set up drag behavoir - eventbox = Gtk.EventBox(visible_window=False) + eventbox = Gtk.Box(visible_window=False) eventbox.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) eventbox.connect("drag-data-get", self._drag_data_get_cb) eventbox.connect("drag-begin", self._drag_begin_cb) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 0dfe23382..0dde34ae3 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -1120,7 +1120,7 @@ class AudioUriSource(TimelineElement): return None -class TrimHandle(Gtk.EventBox, Loggable): +class TrimHandle(Gtk.Box, Loggable): __gtype_name__ = "PitiviTrimHandle" @@ -1129,7 +1129,7 @@ class TrimHandle(Gtk.EventBox, Loggable): PIXBUF = None def __init__(self, clip, edge): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Loggable.__init__(self) self.clip = clip @@ -1150,7 +1150,7 @@ class TrimHandle(Gtk.EventBox, Loggable): self.props.halign = Gtk.Align.START def do_draw(self, cr): - Gtk.EventBox.do_draw(self, cr) + Gtk.Box.do_draw(self, cr) if TrimHandle.PIXBUF is None: TrimHandle.PIXBUF = GdkPixbuf.Pixbuf.new_from_file( os.path.join(get_pixmap_dir(), "trimbar-focused.png")) @@ -1167,12 +1167,12 @@ class TrimHandle(Gtk.EventBox, Loggable): self.props.window.set_cursor(NORMAL_CURSOR) -class Clip(Gtk.EventBox, Loggable): +class Clip(Gtk.Box, Loggable): __gtype_name__ = "PitiviClip" def __init__(self, layer: GES.Layer, ges_clip: GES.Clip): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Loggable.__init__(self) name = ges_clip.get_name() @@ -1300,7 +1300,7 @@ class Clip(Gtk.EventBox, Loggable): handle.shrink() def do_map(self): - Gtk.EventBox.do_map(self) + Gtk.Box.do_map(self) self.update_position() def _button_release_event_cb(self, unused_widget, event): diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index dfb19c437..b2d4b2296 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -43,26 +43,26 @@ VIDEO_ICONS = { } -class SpacedSeparator(Gtk.EventBox): +class SpacedSeparator(Gtk.Box): """A Separator with vertical spacing. - Inherits from EventBox since we want to change background color. + Inherits from Box since we want to change background color. """ def __init__(self): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) self.get_style_context().add_class("SpacedSeparator") self.props.height_request = SEPARATOR_HEIGHT -class LayerControls(Gtk.EventBox, Loggable): +class LayerControls(Gtk.Box, Loggable): """Container with widgets for controlling a layer.""" __gtype_name__ = 'PitiviLayerControls' def __init__(self, ges_layer, app): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Loggable.__init__(self) self.ges_layer = ges_layer diff --git a/pitivi/timeline/markers.py b/pitivi/timeline/markers.py index adb0b5f45..c55005ca0 100644 --- a/pitivi/timeline/markers.py +++ b/pitivi/timeline/markers.py @@ -31,11 +31,11 @@ CLIP_MARKER_HEIGHT = 12 CLIP_MARKER_WIDTH = 10 -class Marker(Gtk.EventBox, Loggable): +class Marker(Gtk.Box, Loggable): """Widget representing a marker.""" def __init__(self, ges_marker, class_name, width, height): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Loggable.__init__(self) self.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | @@ -101,11 +101,11 @@ class Marker(Gtk.EventBox, Loggable): self.unset_state_flags(Gtk.StateFlags.SELECTED) -class MarkersBox(Gtk.EventBox, Zoomable, Loggable): +class MarkersBox(Gtk.Box, Zoomable, Loggable): """Container for displaying and managing markers.""" def __init__(self, app, hadj=None): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Zoomable.__init__(self) Loggable.__init__(self) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 5ad599a34..884a30ba5 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -363,7 +363,7 @@ class MiniLayersLayout(LayersLayout): LayersLayout.update_width(self, width) -class Timeline(Gtk.EventBox, Zoomable, Loggable): +class Timeline(Gtk.Box, Zoomable, Loggable): """Container for the layers controls and representation. Attributes: @@ -373,7 +373,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): __gtype_name__ = "PitiviTimeline" def __init__(self, app, size_group, editor_state): - Gtk.EventBox.__init__(self) + Gtk.Box.__init__(self) Zoomable.__init__(self) Loggable.__init__(self) @@ -398,7 +398,7 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.mini_layout = MiniLayersLayout(self) - self.mini_layout_container = Gtk.EventBox.new() + self.mini_layout_container = Gtk.Box.new() self.mini_layout_container.add(self.mini_layout) self.mini_layout_container.add_events(Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE) self.mini_layout_container.props.no_show_all = True @@ -429,9 +429,6 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable): self.props.expand = True self.get_accessible().set_name("timeline canvas") - # A window is needed to receive BUTTON_* events. This is the reason why - # Timeline is a Gtk.EventBox subclass and not directly a Gtk.Box, - # see `hbox` above. assert self.get_has_window() # A lot of operations go through the handlers of these events. self.add_events(Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE) -- GitLab From fb8fe58e5ae983ec26ce9d0a70e3a26a80919e99 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 13 Jul 2022 16:48:42 +0530 Subject: [PATCH 016/132] Adapt to GtkIconTheme API changes --- pitivi/greeterperspective.py | 6 +++--- pitivi/mainwindow.py | 6 ++++-- pitivi/medialibrary.py | 6 +++--- pitivi/project.py | 3 ++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 47651a24b..8a45ef75c 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -124,9 +124,9 @@ class GreeterPerspective(Perspective): builder.add_from_file(os.path.join(get_ui_dir(), "greeter.ui")) logo = builder.get_object("logo") - icon_theme = Gtk.IconTheme.get_default() - pixbuf = icon_theme.load_icon("org.pitivi.Pitivi", 256, Gtk.IconLookupFlags.FORCE_SIZE) - logo.set_from_pixbuf(pixbuf) + icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) + paintable = icon_theme.lookup_icon("org.pitivi.Pitivi", "", 256, 1, Gtk.TextDirection.NONE, 0) + logo.set_from_paintable(paintable) self.toplevel_widget = builder.get_object("toplevel_vbox") self.toplevel_widget.drag_dest_set( diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index f102e9bb6..09ee3cc1b 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -19,6 +19,7 @@ import os from gettext import gettext as _ from urllib.parse import unquote +from gi.repository import Gdk from gi.repository import Gio from gi.repository import GLib from gi.repository import Gtk @@ -91,8 +92,9 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): os.environ["PULSE_PROP_media.role"] = "production" os.environ["PULSE_PROP_application.icon_name"] = "pitivi" - Gtk.IconTheme.get_default().append_search_path(get_pixmap_dir()) - Gtk.IconTheme.get_default().append_search_path(os.path.join(get_pixmap_dir(), "transitions")) + icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) + icon_theme.add_search_path(get_pixmap_dir()) + icon_theme.add_search_path(os.path.join(get_pixmap_dir(), "transitions")) Gtk.ApplicationWindow.__init__(self) Loggable.__init__(self) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 2ba42d223..c52e0969d 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -443,13 +443,13 @@ class AssetThumbnail(GObject.Object, Loggable): @staticmethod def __get_icon(icon_name, size): - icon_theme = Gtk.IconTheme.get_default() + icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) try: - icon = icon_theme.load_icon(icon_name, size, Gtk.IconLookupFlags.FORCE_SIZE) + icon = icon_theme.lookup_icon(icon_name, "", size, 1, Gtk.TextDirection.NONE, 0) except GLib.Error: # The resulting black question mark is good for light themes but # not the best for the dark ones. - icon = icon_theme.load_icon("dialog-question-symbolic", size, 0) + icon = icon_theme.lookup_icon("dialog-question-symbolic", "", size, 1, Gtk.TextDirection.NONE, 0) return icon def _set_state(self): diff --git a/pitivi/project.py b/pitivi/project.py index d9202e167..ffe5ae0b8 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -28,6 +28,7 @@ from hashlib import md5 from typing import Optional from urllib.parse import unquote +from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import GLib @@ -856,7 +857,7 @@ class Project(Loggable, GES.Project): except GLib.Error: # Try to get the default thumb. try: - thumb = Gtk.IconTheme.get_default().load_icon("video-x-generic", 128, 0) + thumb = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()).lookup_icon("video-x-generic", "", 128, 1, Gtk.TextDirection.NONE, 0) except GLib.Error: return None thumb = scale_pixbuf(thumb, SCALED_THUMB_WIDTH, SCALED_THUMB_HEIGHT) -- GitLab From 310c2ef168210bdd216c09bac682d5e00cb2fe67 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 13 Jul 2022 18:55:22 +0530 Subject: [PATCH 017/132] Use GTK4 matplotlib --- pitivi/timeline/elements.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 0dde34ae3..1d30b2d1c 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -29,7 +29,7 @@ from gi.repository import GstController from gi.repository import Gtk from matplotlib.axes import Axes from matplotlib.backend_bases import MouseButton -from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo +from matplotlib.backends.backend_gtk4cairo import FigureCanvasGTK4Cairo from matplotlib.collections import PathCollection from matplotlib.figure import Figure from matplotlib.lines import Line2D @@ -76,7 +76,7 @@ def get_pspec(element_factory_name, propname): return [prop for prop in element.list_properties() if prop.name == propname][0] -class KeyframeCurve(FigureCanvasGTK3Cairo, Loggable): +class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): YLIM_OVERRIDES = {} __YLIM_OVERRIDES_VALUES = [("volume", "volume", (0.0, 0.2))] @@ -95,7 +95,7 @@ class KeyframeCurve(FigureCanvasGTK3Cairo, Loggable): def __init__(self, timeline, binding, ges_elem): figure = Figure() - FigureCanvasGTK3Cairo.__init__(self, figure) + FigureCanvasGTK4Cairo.__init__(self, figure) Loggable.__init__(self) # Remove the "matplotlib-canvas" class which forces a white background. -- GitLab From 420430d77173c913ac5b9ee5e0523a65f96bd91c Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 15 Jul 2022 00:29:38 +0530 Subject: [PATCH 018/132] Replace deprecated GdkScreen --- pitivi/dialogs/prefs.py | 6 +++--- pitivi/editorperspective.py | 6 +++--- pitivi/greeterperspective.py | 6 +++--- pitivi/interactiveintro.py | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index a9cd2b413..39e266abf 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -108,10 +108,10 @@ class PreferencesDialog(Loggable): def __setup_css(self): css_provider = Gtk.CssProvider() css_provider.load_from_data(PREFERENCES_CSS.encode('UTF-8')) - screen = Gdk.Screen.get_default() + display = Gdk.Display.get_default() style_context = self.app.gui.get_style_context() - style_context.add_provider_for_screen(screen, css_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + style_context.add_provider_for_display(display, css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) # Public API diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 574f15eef..b99ead8ee 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -117,10 +117,10 @@ class EditorPerspective(Perspective, Loggable): def __setup_css(self): css_provider = Gtk.CssProvider() css_provider.load_from_data(EDITOR_PERSPECTIVE_CSS.encode("UTF-8")) - screen = Gdk.Screen.get_default() + display = Gdk.Display.get_default() style_context = self.app.gui.get_style_context() - style_context.add_provider_for_screen(screen, css_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + style_context.add_provider_for_display(display, css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) def __focus_in_event_cb(self, unused_widget, unused_event): ges_timeline = self.timeline_ui.timeline.ges_timeline diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 8a45ef75c..f9f00df40 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -217,10 +217,10 @@ class GreeterPerspective(Perspective): def __setup_css(self): css_provider = Gtk.CssProvider() css_provider.load_from_data(GREETER_PERSPECTIVE_CSS.encode('UTF-8')) - screen = Gdk.Screen.get_default() + display = Gdk.Display.get_default() style_context = self.app.gui.get_style_context() - style_context.add_provider_for_screen(screen, css_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + style_context.add_provider_for_display(display, css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) def __create_headerbar(self): headerbar = Gtk.HeaderBar() diff --git a/pitivi/interactiveintro.py b/pitivi/interactiveintro.py index 31a85606e..c980483bf 100644 --- a/pitivi/interactiveintro.py +++ b/pitivi/interactiveintro.py @@ -86,10 +86,10 @@ class InteractiveIntro(GObject.Object): def __setup_css(self): css_provider = Gtk.CssProvider() css_provider.load_from_data(INTERACTIVE_INTRO_CSS.encode("UTF-8")) - screen = Gdk.Screen.get_default() + display = Gdk.Display.get_default() style_context = self.app.gui.get_style_context() - style_context.add_provider_for_screen(screen, css_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + style_context.add_provider_for_display(display, css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) def __create_intro_button(self): """Creates a button for controlling the intro.""" -- GitLab From d14dd41f6a22061d49477fb99beaa89fbd94ed8e Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 15 Jul 2022 03:14:48 +0530 Subject: [PATCH 019/132] Replace GtkButton Image API --- data/ui/beatdetection.ui | 8 +-- data/ui/clipcompositing.ui | 14 +---- data/ui/cliptransformation.ui | 14 +---- data/ui/customwidgets/alpha.ui | 35 ++---------- .../frei0r-filter-3-point-color-balance.ui | 21 +------ .../customwidgets/frei0r-filter-alphaspot.ui | 56 +++---------------- data/ui/effectslibrary.ui | 1 - data/ui/mainmenubutton.ui | 8 +-- data/ui/projectsettings.ui | 8 +-- data/ui/renderingdialog.ui | 16 +----- data/ui/trackerperspective.ui | 30 ++-------- pitivi/clipproperties.py | 9 ++- pitivi/dialogs/prefs.py | 7 +-- pitivi/editorperspective.py | 12 +--- pitivi/effects.py | 4 +- pitivi/greeterperspective.py | 5 +- pitivi/interactiveintro.py | 6 +- pitivi/medialibrary.py | 3 +- pitivi/project.py | 5 +- pitivi/timeline/layer.py | 7 +-- pitivi/trackerperspective.py | 12 ++-- pitivi/utils/widgets.py | 8 +-- pitivi/viewer/viewer.py | 29 ++++------ tests/plugins/test_alpha.ui | 14 +---- 24 files changed, 70 insertions(+), 262 deletions(-) diff --git a/data/ui/beatdetection.ui b/data/ui/beatdetection.ui index 977481430..2935e7e37 100644 --- a/data/ui/beatdetection.ui +++ b/data/ui/beatdetection.ui @@ -34,14 +34,8 @@ True fill Clear detected beats + edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - 1 diff --git a/data/ui/clipcompositing.ui b/data/ui/clipcompositing.ui index e362b2ca5..231f3bce3 100644 --- a/data/ui/clipcompositing.ui +++ b/data/ui/clipcompositing.ui @@ -14,16 +14,6 @@ 5 - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - True @@ -151,7 +141,7 @@ False True Reset fade-in - icon_reset1 + edit-clear-all-symbolic none @@ -167,7 +157,7 @@ False True Reset fade-out - icon_reset2 + edit-clear-all-symbolic none diff --git a/data/ui/cliptransformation.ui b/data/ui/cliptransformation.ui index 5d6d8fffb..772bf5059 100644 --- a/data/ui/cliptransformation.ui +++ b/data/ui/cliptransformation.ui @@ -9,16 +9,6 @@ 1 10 - - True - False - chain-connected-symbolic - - - True - False - edit-clear-all-symbolic - -9999999999 9999999999 @@ -140,7 +130,7 @@ True Constrain Proportions True - aspect_ratio_image + chain-connected-symbolic none @@ -222,7 +212,7 @@ False True Reset to default values - icon_reset1 + edit-clear-all-symbolic none True fill diff --git a/data/ui/customwidgets/alpha.ui b/data/ui/customwidgets/alpha.ui index f63243afd..4e7d1a2e0 100644 --- a/data/ui/customwidgets/alpha.ui +++ b/data/ui/customwidgets/alpha.ui @@ -31,31 +31,6 @@ 1 10 - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - 64 @@ -88,7 +63,7 @@ True True True - image1 + edit-clear-all-symbolic none top @@ -102,7 +77,7 @@ True True True - image2 + edit-clear-all-symbolic none top @@ -116,7 +91,7 @@ True True True - image3 + edit-clear-all-symbolic none top @@ -130,7 +105,7 @@ True True True - image4 + edit-clear-all-symbolic none top @@ -441,7 +416,7 @@ True True True - image5 + edit-clear-all-symbolic none top diff --git a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui index 3be8f5fd5..e3d102ff6 100644 --- a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui +++ b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui @@ -48,21 +48,6 @@ 10 - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - True False @@ -297,7 +282,7 @@ True True True - image2 + edit-clear-all-symbolic top @@ -347,7 +332,7 @@ True True True - image1 + edit-clear-all-symbolic top @@ -397,7 +382,7 @@ True True True - image3 + edit-clear-all-symbolic top diff --git a/data/ui/customwidgets/frei0r-filter-alphaspot.ui b/data/ui/customwidgets/frei0r-filter-alphaspot.ui index ad2a27f26..2a3429b7a 100644 --- a/data/ui/customwidgets/frei0r-filter-alphaspot.ui +++ b/data/ui/customwidgets/frei0r-filter-alphaspot.ui @@ -50,46 +50,6 @@ 0.01 0.10000000000000001 - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - - - True - False - edit-clear-all-symbolic - True False @@ -104,7 +64,7 @@ True True True - image1 + edit-clear-all-symbolic none top @@ -118,7 +78,7 @@ True True True - image2 + edit-clear-all-symbolic none top @@ -132,7 +92,7 @@ True True True - image3 + edit-clear-all-symbolic none top @@ -146,7 +106,7 @@ True True True - image4 + edit-clear-all-symbolic none top @@ -545,7 +505,7 @@ True True True - image6 + edit-clear-all-symbolic none top @@ -559,7 +519,7 @@ True True True - image7 + edit-clear-all-symbolic none top @@ -573,7 +533,7 @@ True True True - image9 + edit-clear-all-symbolic none top @@ -587,7 +547,7 @@ True True True - image10 + edit-clear-all-symbolic none top diff --git a/data/ui/effectslibrary.ui b/data/ui/effectslibrary.ui index 6d6c0f1cb..c8495c1cd 100644 --- a/data/ui/effectslibrary.ui +++ b/data/ui/effectslibrary.ui @@ -17,7 +17,6 @@ True True True - True diff --git a/data/ui/mainmenubutton.ui b/data/ui/mainmenubutton.ui index 45b7d1f47..d383ef6b7 100644 --- a/data/ui/mainmenubutton.ui +++ b/data/ui/mainmenubutton.ui @@ -217,12 +217,6 @@ True True menu - - - True - False - open-menu-symbolic - - + open-menu-symbolic diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index a4909566f..b20e918b8 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -170,13 +170,7 @@ True none fill - - - True - False - open-menu-symbolic - - + open-menu-symbolic 2 diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index 142319c4c..0173dec7c 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -15,11 +15,6 @@ 1 - - True - False - question-round-symbolic - @@ -197,13 +192,7 @@ True start none - - - True - False - open-menu-symbolic - - + open-menu-symbolic 1 @@ -273,9 +262,8 @@ True True True - help_icon + question-round-symbolic none - True fill diff --git a/data/ui/trackerperspective.ui b/data/ui/trackerperspective.ui index 475c70675..2142f5222 100644 --- a/data/ui/trackerperspective.ui +++ b/data/ui/trackerperspective.ui @@ -13,34 +13,12 @@ - - True - False - Pause - media-playback-pause-symbolic - - - True - False - Play - media-playback-start-symbolic - 100 1 10 - - True - False - media-seek-backward-symbolic - - - True - False - media-seek-forward-symbolic - diff --git a/tests/plugins/test_alpha.ui b/tests/plugins/test_alpha.ui index f1565e761..34c517345 100644 --- a/tests/plugins/test_alpha.ui +++ b/tests/plugins/test_alpha.ui @@ -29,11 +29,11 @@ False Alpha: 0 + + 1 + 1 + - - 1 - 1 - @@ -46,11 +46,11 @@ 2 left True + + 2 + 1 + - - 2 - 1 - @@ -58,11 +58,11 @@ False Black sensitivity: 0 + + 1 + 0 + - - 1 - 0 - @@ -75,11 +75,11 @@ 0 left True + + 2 + 0 + - - 2 - 0 - @@ -88,11 +88,11 @@ True True False + + 0 + 0 + - - 0 - 0 - @@ -102,11 +102,11 @@ edit-clear-all-symbolic False top + + 3 + 0 + - - 3 - 0 - @@ -116,11 +116,11 @@ edit-clear-all-symbolic False top + + 3 + 1 + - - 3 - 1 - -- GitLab From ed356766809d7ef8990cf64a8a15e692bbd74582 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 4 Aug 2022 00:28:53 +0530 Subject: [PATCH 042/132] Adapt to GtkLabel change --- pitivi/clip_properties/markers.py | 2 +- pitivi/clipproperties.py | 8 ++++---- pitivi/dialogs/prefs.py | 4 ++-- pitivi/editorperspective.py | 8 ++++---- pitivi/effects.py | 7 ++++--- pitivi/greeterperspective.py | 10 +++++----- pitivi/mediafilespreviewer.py | 2 +- pitivi/medialibrary.py | 2 +- pitivi/render.py | 2 +- pitivi/tabsmanager.py | 4 ++-- pitivi/trackerperspective.py | 2 +- pitivi/utils/widgets.py | 10 +++++----- pitivi/viewer/guidelines.py | 4 ++-- pitivi/viewer/overlay_stack.py | 2 +- 14 files changed, 34 insertions(+), 33 deletions(-) diff --git a/pitivi/clip_properties/markers.py b/pitivi/clip_properties/markers.py index 2acc784d5..827012bcc 100644 --- a/pitivi/clip_properties/markers.py +++ b/pitivi/clip_properties/markers.py @@ -103,7 +103,7 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): child_type = child.get_track_type() name = ClipMarkersProperties.TRACK_TYPES[child_type] - label = Gtk.Label(label=name) + label = Gtk.Label.new(name) row_box.prepend(label) label.show() labels_size_group.add_widget(label) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index 16920c69e..11b2a916f 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -158,7 +158,7 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.props.margin = PADDING - label = Gtk.Label(label=_("Select a clip on the timeline to configure its properties and effects or create a new clip:")) + label = Gtk.Label.new(_("Select a clip on the timeline to configure its properties and effects or create a new clip:")) label.set_wrap(True) label.set_xalign(0) label.props.margin_top = SPACING @@ -359,7 +359,7 @@ class TimeProperties(Gtk.Expander, Loggable): button.set_has_frame(False) button.connect("clicked", reset_func) - label = Gtk.Label(label=text) + label = Gtk.Label.new(text) label.props.yalign = 0.5 grid.attach(label, 0, y, 1, 1) grid.attach(widget, 1, y, 1, 1) @@ -607,7 +607,7 @@ class EffectProperties(Gtk.Expander, Loggable): self.expander_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.effects_listbox = Gtk.ListBox() - placeholder_label = Gtk.Label( + placeholder_label = Gtk.Label.new( _("To apply an effect to the clip, drag it from the Effect Library " "or use the button below.")) placeholder_label.set_wrap(True) @@ -678,7 +678,7 @@ class EffectProperties(Gtk.Expander, Loggable): toggle.props.margin_end = PADDING effect_info = self.app.effects.get_info(effect) - effect_label = Gtk.Label(effect_info.human_name) + effect_label = Gtk.Label.new(effect_info.human_name) effect_label.set_tooltip_text(effect_info.description) # Set up revealer + expander diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 6e670b21e..4b9ad0999 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -247,7 +247,7 @@ class PreferencesDialog(Loggable): for y, (label, widget, revert_widget, extra_widget) in enumerate(prefs): box = Gtk.Box() - label_widget = Gtk.Label(label=label) + label_widget = Gtk.Label.new(label) label_widget.set_alignment(0.0, 0.5) label_widget.props.margin_end = PADDING * 3 label_widget.props.margin_top = PADDING * 2 @@ -333,7 +333,7 @@ class PreferencesDialog(Loggable): self.widgets["default_scaled_proxy_height"] = self.proxy_height_widget size_box = Gtk.Box(spacing=SPACING) size_box.prepend(self.proxy_width_widget) - size_box.prepend(Gtk.Label("×")) + size_box.prepend(Gtk.Label.new("×")) size_box.prepend(self.proxy_height_widget) size_box.set_tooltip_text(_("This resolution will be used as the" " default target resolution for new projects and projects missing" diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 7e54093da..216f65e2b 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -202,9 +202,9 @@ class EditorPerspective(Perspective, Loggable): self.medialibrary = MediaLibraryWidget(self.app) self.effectlist = EffectListWidget(self.app) self.main_tabs.append_page("Media Library", - self.medialibrary, Gtk.Label(label=_("Media Library"))) + self.medialibrary, Gtk.Label.new(_("Media Library"))) self.main_tabs.append_page("Effect Library", - self.effectlist, Gtk.Label(label=_("Effect Library"))) + self.effectlist, Gtk.Label.new(_("Effect Library"))) self.medialibrary.connect('play', self._media_library_play_cb) self.medialibrary.show() self.effectlist.show() @@ -214,9 +214,9 @@ class EditorPerspective(Perspective, Loggable): self.clipconfig = ClipProperties(self.app) self.trans_list = TransitionsListWidget(self.app) self.context_tabs.append_page("Clip", - self.clipconfig, Gtk.Label(label=_("Clip"))) + self.clipconfig, Gtk.Label.new(_("Clip"))) self.context_tabs.append_page("Transition", - self.trans_list, Gtk.Label(label=_("Transition"))) + self.trans_list, Gtk.Label.new(_("Transition"))) # Show by default the Title tab, as the Clip and Transition tabs # are useful only when a clip or transition is selected, but # the Title tab allows adding titles. diff --git a/pitivi/effects.py b/pitivi/effects.py index 75f62d925..6fbae0423 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -407,7 +407,7 @@ class EffectListWidget(Gtk.Box, Loggable): self.search_view = Gtk.ListBox(activate_on_single_click=False) self.search_view.connect("row-activated", self.effects_listbox_row_activated_cb) - placeholder_text = Gtk.Label(_("No effects")) + placeholder_text = Gtk.Label.new(_("No effects")) placeholder_text.props.visible = True self.search_view.set_placeholder(placeholder_text) self.search_view.set_hexpand(True) @@ -485,7 +485,8 @@ class EffectListWidget(Gtk.Box, Loggable): effect_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, margin=SPACING / 2) effect_box.effect_name = effect_name effect_box.set_tooltip_text(effect_info.description) - label = Gtk.Label(effect_info.human_name, xalign=0) + label = Gtk.Label.new(effect_info.human_name) + label.set_xalign(0) label.set_halign(Gtk.Align.FILL) label.set_hexpand(True) @@ -685,7 +686,7 @@ class EffectsPopover(Gtk.Popover, Loggable): self.listbox = Gtk.ListBox() self.listbox.connect("row-activated", self._effect_row_activate_cb) self.listbox.set_filter_func(self._search_filter) - placeholder_text = Gtk.Label(_("No effects")) + placeholder_text = Gtk.Label.new(_("No effects")) placeholder_text.props.visible = True self.listbox.set_placeholder(placeholder_text) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 00d13ca2a..4e93a1ca7 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -363,7 +363,7 @@ class GreeterPerspective(Perspective): # increment counter, create infobar and show info self.app.settings.displayCounter += 1 text = _("Pitivi %s is available.") % latest_version - label = Gtk.Label(label=text) + label = Gtk.Label.new(text) self.__infobar.add_child(label) self.__infobar.set_message_type(Gtk.MessageType.INFO) self.__infobar.show() @@ -438,7 +438,7 @@ class GreeterPerspective(Perspective): popover = Gtk.Popover() box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, margin=PADDING * 3) - label = Gtk.Label(_("To enable additional features, please install the following packages and restart Pitivi:")) + label = Gtk.Label.new(_("To enable additional features, please install the following packages and restart Pitivi:")) label.props.halign = Gtk.Align.START label.props.wrap = True label.props.xalign = 0 @@ -451,19 +451,19 @@ class GreeterPerspective(Perspective): grid.props.margin_top = SPACING * 2 for row_index, dep in enumerate(MISSING_SOFT_DEPS.values()): - name_label = Gtk.Label(dep.modulename) + name_label = Gtk.Label.new(dep.modulename) name_label.props.selectable = True name_label.props.can_focus = False name_label.props.xalign = 0 name_label.props.valign = Gtk.Align.START grid.attach(name_label, 0, row_index, 1, 1) - mdash_label = Gtk.Label("―") + mdash_label = Gtk.Label.new("―") mdash_label.props.xalign = 0 mdash_label.props.valign = Gtk.Align.START grid.attach(mdash_label, 1, row_index, 1, 1) - description_label = Gtk.Label(dep.additional_message) + description_label = Gtk.Label.new(dep.additional_message) description_label.props.wrap = True description_label.props.xalign = 0 description_label.props.yalign = Gtk.Align.START diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index 6aad42faa..6f4d8d3b9 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -155,7 +155,7 @@ class PreviewWidget(Gtk.Grid, Loggable): vbox = Gtk.Box() vbox.set_orientation(Gtk.Orientation.VERTICAL) vbox.set_spacing(SPACING) - self.l_error = Gtk.Label(label=_("Pitivi can not preview this file.")) + self.l_error = Gtk.Label.new(_("Pitivi can not preview this file.")) self.l_error.set_hexpand(True) self.l_error.set_halign(Gtk.Align.FILL) self.b_details = Gtk.Button.new_with_label(_("More info")) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index e56494d2d..14118763d 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -1182,7 +1182,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): def _tags_button_clicked_cb(self, unused_widget): self.tags_popover = Gtk.Popover() - popover_heading = Gtk.Label(label=_("Tag as:")) + popover_heading = Gtk.Label.new(_("Tag as:")) popover_heading.set_halign(Gtk.Align.START) paths = self.get_selected_paths() diff --git a/pitivi/render.py b/pitivi/render.py index d26baaab6..4ce818248 100644 --- a/pitivi/render.py +++ b/pitivi/render.py @@ -148,7 +148,7 @@ class PresetBoxRow(Gtk.ListBoxRow): icon = Gtk.Image() set_icon_and_title(icon, title, preset_item) - description = Gtk.Label(preset_item.target.get_description()) + description = Gtk.Label.new(preset_item.target.get_description()) description.set_xalign(0) description.set_wrap(True) description.props.max_width_chars = 30 diff --git a/pitivi/tabsmanager.py b/pitivi/tabsmanager.py index 8f27a5a99..c473da028 100644 --- a/pitivi/tabsmanager.py +++ b/pitivi/tabsmanager.py @@ -59,7 +59,7 @@ class BaseTabs(Gtk.Notebook, Loggable): original_position = self.page_num(child) self.remove_page(original_position) # Add the tab to the notebook in our newly created window. - notebook.append_page(child, Gtk.Label(label=child_name)) + notebook.append_page(child, Gtk.Label.new(child_name)) child.show() def _set_child_properties(self, child, label): @@ -74,7 +74,7 @@ class BaseTabs(Gtk.Notebook, Loggable): position = notebook.page_num(child) notebook.remove_page(position) setattr(self.settings, child_name + "docked", True) - label = Gtk.Label(label=child_name) + label = Gtk.Label.new(child_name) self.insert_page(child, label, original_position) self._set_child_properties(child, label) diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index 6531facec..f73e8302f 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -183,7 +183,7 @@ class TrackedObjectRow(Gtk.ListBoxRow): self.object_id: str = object_id self.name: str = name - label = Gtk.Label(name) + label = Gtk.Label.new(name) label.props.margin = SPACING label.props.margin_end = PADDING label.props.margin_start = PADDING diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index cf6906c2b..2933a12b4 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -802,7 +802,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): grid.attach(widget, 0, y, 2, 1) else: text = _("%(preference_label)s:") % {"preference_label": nick} - label = Gtk.Label(label=text) + label = Gtk.Label.new(text) label.props.yalign = 0.5 grid.attach(label, 0, y, 1, 1) grid.attach(widget, 1, y, 1, 1) @@ -837,7 +837,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): props = [prop for prop in GObject.list_properties(self.element) if prop.name not in self.ignore] if not props: - widget = Gtk.Label(label=_("No properties.")) + widget = Gtk.Label.new(_("No properties.")) self.prepend(widget) widget.show() return @@ -904,7 +904,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): except KeyError: widget = prop_widget - label = Gtk.Label(label=prop.nick) + label = Gtk.Label.new(prop.nick) label.set_alignment(0.0, 0.5) grid.attach(label, 0, y, 1, 1) grid.attach(widget, 1, y, 1, 1) @@ -1233,7 +1233,7 @@ class ZoomBox(Gtk.Grid, Zoomable): zoom_fit_btn_grid = Gtk.Grid() zoom_fit_icon = Gtk.Image.new_from_icon_name("zoom-fit-best-symbolic") zoom_fit_btn_grid.add(zoom_fit_icon) - zoom_fit_btn_label = Gtk.Label(label=_("Zoom")) + zoom_fit_btn_label = Gtk.Label.new(_("Zoom")) zoom_fit_btn_grid.add(zoom_fit_btn_label) zoom_fit_btn_grid.set_column_spacing(SPACING / 2) zoom_fit_btn.set_child(zoom_fit_btn_grid) @@ -1259,7 +1259,7 @@ class ZoomBox(Gtk.Grid, Zoomable): self.attach(zoomslider, 1, 0, 1, 1) # Empty label so we have some spacing at the right of the zoomslider - self.attach(Gtk.Label(label=""), 2, 0, 1, 1) + self.attach(Gtk.Label.new(""), 2, 0, 1, 1) self.set_hexpand(False) self.set_column_spacing(ZOOM_SLIDER_PADDING) diff --git a/pitivi/viewer/guidelines.py b/pitivi/viewer/guidelines.py index b72d66ffa..b506485ac 100644 --- a/pitivi/viewer/guidelines.py +++ b/pitivi/viewer/guidelines.py @@ -89,7 +89,7 @@ class GuidelinesPopover(Gtk.Popover): grid.props.column_spacing = SPACING grid.props.margin = SPACING * 2 - label = Gtk.Label(_("Composition Guidelines")) + label = Gtk.Label.new(_("Composition Guidelines")) label.props.wrap = True grid.attach(label, 0, 0, 2, 1) @@ -99,7 +99,7 @@ class GuidelinesPopover(Gtk.Popover): for guideline in Guideline: row += 1 - label = Gtk.Label(guideline.label) + label = Gtk.Label.new(guideline.label) label.props.halign = Gtk.Align.START label.props.wrap = True label.props.xalign = 0 diff --git a/pitivi/viewer/overlay_stack.py b/pitivi/viewer/overlay_stack.py index 666abceae..349f4204d 100644 --- a/pitivi/viewer/overlay_stack.py +++ b/pitivi/viewer/overlay_stack.py @@ -59,7 +59,7 @@ class OverlayStack(Gtk.Overlay, Loggable): # ID of resizing timeout callback, so it can be delayed. self.__resizing_id = 0 self.revealer = Gtk.Revealer(transition_type=Gtk.RevealerTransitionType.CROSSFADE) - self.resize_status = Gtk.Label(name="resize_status") + self.resize_status = Gtk.Label.new(name="resize_status") self.revealer.set_child(self.resize_status) self.add_overlay(self.revealer) -- GitLab From b2b17236c9364ed2e9c3d0d83bb66d32e64a57f1 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 4 Aug 2022 00:42:04 +0530 Subject: [PATCH 043/132] Drop use of visible_window --- pitivi/effects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/effects.py b/pitivi/effects.py index 6fbae0423..56e76c770 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -519,7 +519,7 @@ class EffectListWidget(Gtk.Box, Loggable): effect_box.prepend(label) # Set up drag behavoir - eventbox = Gtk.Box(visible_window=False) + eventbox = Gtk.Box() eventbox.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) eventbox.connect("drag-data-get", self._drag_data_get_cb) eventbox.connect("drag-begin", self._drag_begin_cb) -- GitLab From 44d3716ba35741293a7dbd42b0ad150570abea29 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 4 Aug 2022 00:52:38 +0530 Subject: [PATCH 044/132] Drop use of GtkActionGroup --- data/ui/cliptransformation.ui | 1 - 1 file changed, 1 deletion(-) diff --git a/data/ui/cliptransformation.ui b/data/ui/cliptransformation.ui index a55635854..86bc522e7 100644 --- a/data/ui/cliptransformation.ui +++ b/data/ui/cliptransformation.ui @@ -2,7 +2,6 @@ - 1 9999999999 -- GitLab From 5690f64db611aee052ff4359bf58fa353cd56750 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 4 Aug 2022 01:23:33 +0530 Subject: [PATCH 045/132] Adapt to GtkMenuButton changes --- pitivi/clipproperties.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index 11b2a916f..f5cce9955 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -616,7 +616,9 @@ class EffectProperties(Gtk.Expander, Loggable): # Add effect popover button self.effect_popover = EffectsPopover(app) - self.add_effect_button = Gtk.MenuButton(_("Add Effect")) + self.add_effect_button = Gtk.MenuButton() + self.add_effect_button.set_label(_("Add Effect")) + self.add_effect_button.set_direction(Gtk.ArrowType.NONE) self.add_effect_button.set_popover(self.effect_popover) self.add_effect_button.props.halign = Gtk.Align.CENTER self.add_effect_button.props.margin_top = PADDING @@ -634,7 +636,9 @@ class EffectProperties(Gtk.Expander, Loggable): self.cover_popover: Optional[Gtk.Popover] = None self.cover_object_button: Optional[Gtk.MenuButton] = None if "cvtracker" not in MISSING_SOFT_DEPS: - self.cover_object_button = Gtk.MenuButton(_("Cover Object")) + self.cover_object_button = Gtk.MenuButton() + self.cover_object_button.set_label(_("Cover Object")) + self.cover_object_button.set_direction(Gtk.ArrowType.NONE) self.object_tracker_box.prepend(self.cover_object_button) self.drag_dest_set(Gtk.DestDefaults.DROP, [EFFECT_TARGET_ENTRY], -- GitLab From 5e677f3da812b969ba5a2d9ce8e3d20dd13caac3 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 18 Aug 2022 23:46:26 +0530 Subject: [PATCH 046/132] Fix greeter logo size --- pitivi/greeterperspective.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 4e93a1ca7..8dcee3796 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -126,6 +126,7 @@ class GreeterPerspective(Perspective): icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) paintable = icon_theme.lookup_icon("org.pitivi.Pitivi", "", 256, 1, Gtk.TextDirection.NONE, 0) logo.set_from_paintable(paintable) + logo.set_pixel_size(256) self.toplevel_widget = builder.get_object("toplevel_vbox") self.toplevel_widget.drag_dest_set( -- GitLab From 34aa8a45053ddae5bcfba0806af1fb9c219f836d Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 18 Aug 2022 23:50:58 +0530 Subject: [PATCH 047/132] About window GTK version change --- pitivi/dialogs/about.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/dialogs/about.py b/pitivi/dialogs/about.py index 1d8de7930..449dd3126 100644 --- a/pitivi/dialogs/about.py +++ b/pitivi/dialogs/about.py @@ -51,7 +51,7 @@ class AboutDialog(Gtk.AboutDialog): comments = ["", "GES %s" % ".".join(map(str, GES.version())), - "GTK+ %s" % ".".join(map(str, (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION))), + "GTK %s" % ".".join(map(str, (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION))), "GStreamer %s" % ".".join(map(str, Gst.version()))] self.set_comments("\n".join(comments)) -- GitLab From 1050bfad7c4b2ebd5dbf36c656d3f29768aa4d19 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 19 Aug 2022 00:16:10 +0530 Subject: [PATCH 048/132] Adapt to GDateTime changes --- pitivi/greeterperspective.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 8dcee3796..49da93546 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -70,7 +70,7 @@ class ProjectInfoRow(Gtk.ListBoxRow): builder.get_object("project_uri_label").set_text( beautify_project_path(recent_project_item.get_uri_display())) builder.get_object("project_last_updated_label").set_text( - beautify_last_updated_timestamp(recent_project_item.get_modified())) + beautify_last_updated_timestamp(recent_project_item.get_modified().to_unix())) def __load_thumb_cb(self): self.__thumb.set_from_pixbuf(Project.get_thumb(self.uri)) -- GitLab From b585e403ec7d97ad74e0df4b675716f7f88cc819 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 19 Aug 2022 00:59:37 +0530 Subject: [PATCH 049/132] Adapt to GtkPopoverMenu change --- data/ui/mainmenubutton.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/ui/mainmenubutton.ui b/data/ui/mainmenubutton.ui index 631b0b6d4..55aebf91e 100644 --- a/data/ui/mainmenubutton.ui +++ b/data/ui/mainmenubutton.ui @@ -4,7 +4,7 @@ False - + True False @@ -167,7 +167,7 @@ - + True -- GitLab From f2f7a037381d0d276957869d3f13f1cbecd791d6 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Mon, 22 Aug 2022 19:30:54 +0530 Subject: [PATCH 050/132] Replace deprecated get_children --- pitivi/clip_properties/markers.py | 2 +- pitivi/clipproperties.py | 7 ++++--- pitivi/dialogs/filelisterrordialog.py | 4 +++- pitivi/dialogs/prefs.py | 5 +++-- pitivi/effects.py | 18 ++++++++++-------- pitivi/greeterperspective.py | 12 ++++++------ pitivi/timeline/elements.py | 3 ++- pitivi/timeline/markers.py | 5 +++-- pitivi/timeline/previewers.py | 5 +++-- pitivi/trackerperspective.py | 2 +- pitivi/utils/ui.py | 22 +++++++++++++++++++++- tests/common.py | 7 ++++--- tests/test_medialibrary.py | 5 +++-- tests/test_trackerperspective.py | 7 ++++--- 14 files changed, 68 insertions(+), 36 deletions(-) diff --git a/pitivi/clip_properties/markers.py b/pitivi/clip_properties/markers.py index 827012bcc..25d5dd254 100644 --- a/pitivi/clip_properties/markers.py +++ b/pitivi/clip_properties/markers.py @@ -75,7 +75,7 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): disconnect_all_by_func(child.markers_manager, self._lists_modified_cb) disconnect_all_by_func(child.markers_manager, self._current_list_changed_cb) - for child in self.expander_box.get_children(): + while child := self.expander_box.get_first_child(): self.expander_box.remove(child) self.clip = clip diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index f5cce9955..b2aeb2785 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -55,6 +55,7 @@ from pitivi.utils.pipeline import PipelineError from pitivi.utils.timeline import SELECT from pitivi.utils.ui import disable_scroll from pitivi.utils.ui import EFFECT_TARGET_ENTRY +from pitivi.utils.ui import get_listbox_children from pitivi.utils.ui import PADDING from pitivi.utils.ui import SPACING @@ -740,7 +741,7 @@ class EffectProperties(Gtk.Expander, Loggable): return row def _update_listbox(self): - for row in self.effects_listbox.get_children(): + while row := self.effects_listbox.get_row_at_index(0): self.effects_listbox.remove(row) for effect in self.clip.get_top_effects(): @@ -757,7 +758,7 @@ class EffectProperties(Gtk.Expander, Loggable): revealer.props.reveal_child = expander.props.expanded def _get_effect_row(self, effect): - for row in self.effects_listbox.get_children(): + for row in get_listbox_children(self.effects_listbox): if row.effect == effect: return row return None @@ -913,7 +914,7 @@ class EffectProperties(Gtk.Expander, Loggable): # Drop happened inside the lisbox drop_index = widget.get_index() else: - drop_index = len(self.effects_listbox.get_children()) - 1 + drop_index = len(get_listbox_children(self.effects_listbox)) - 1 if drag_context.get_suggested_action() == Gdk.DragAction.COPY: # An effect dragged probably from the effects list. diff --git a/pitivi/dialogs/filelisterrordialog.py b/pitivi/dialogs/filelisterrordialog.py index 74833d5fd..22c4a8b85 100644 --- a/pitivi/dialogs/filelisterrordialog.py +++ b/pitivi/dialogs/filelisterrordialog.py @@ -25,6 +25,7 @@ from gi.repository import Pango from pitivi.configure import get_ui_dir from pitivi.utils.loggable import Loggable +from pitivi.utils.ui import get_widget_children class FileListErrorDialog(GObject.Object, Loggable): @@ -59,7 +60,8 @@ class FileListErrorDialog(GObject.Object, Loggable): self.debug("Uri: %s, reason: %s, extra: %s", uri, reason, extra) exp = self.__create_file_expander(uri, reason, extra) self.errorvbox.prepend(exp) - if len(self.errorvbox.get_children()) < 3: + # ToDo: Use size instead + if len(get_widget_children(self.errorvbox)) < 3: exp.set_expanded(True) # Let's save the user some clicks @staticmethod diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 4b9ad0999..5bead6ca4 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -33,6 +33,7 @@ from pitivi.settings import GlobalSettings from pitivi.utils import widgets from pitivi.utils.loggable import Loggable from pitivi.utils.ui import alter_style_class +from pitivi.utils.ui import get_listbox_children from pitivi.utils.ui import PADDING from pitivi.utils.ui import PREFERENCES_CSS from pitivi.utils.ui import SPACING @@ -799,7 +800,7 @@ class PluginsBox(Gtk.ListBox): # Activate the plugins' switches for plugins that are already loaded. loaded_plugins = self.app.plugin_manager.engine.get_loaded_plugins() - for row in self.get_children(): + for row in get_listbox_children(self): if row.plugin_info.get_module_name() in loaded_plugins: row.switch.set_active(True) @@ -810,7 +811,7 @@ class PluginsBox(Gtk.ListBox): def get_row(self, module_name): """Gets the PluginPreferencesRow linked to a given module name.""" - for row in self.get_children(): + for row in get_listbox_children(self): if row.plugin_info.get_module_name() == module_name: return row return None diff --git a/pitivi/effects.py b/pitivi/effects.py index 56e76c770..bd4c5f855 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -52,6 +52,8 @@ from pitivi.trackerperspective import EFFECT_TRACKED_OBJECT_NAME_META from pitivi.utils.loggable import Loggable from pitivi.utils.ui import disable_scroll from pitivi.utils.ui import EFFECT_TARGET_ENTRY +from pitivi.utils.ui import get_listbox_children +from pitivi.utils.ui import get_widget_children from pitivi.utils.ui import PADDING from pitivi.utils.ui import SPACING from pitivi.utils.widgets import FractionWidget @@ -444,7 +446,7 @@ class EffectListWidget(Gtk.Box, Loggable): self.category_view.append(widget) # Add effects to category expanders - for expander in self.category_view.get_children(): + for expander in get_widget_children(self.category_view): listbox = expander.get_child() category_name = expander.get_label() @@ -594,16 +596,16 @@ class EffectListWidget(Gtk.Box, Loggable): # Get all listboxes which contain the effect effect_info = self.app.effects.get_info(effect) all_effect_listboxes = [category_expander.get_child() - for category_expander in self.category_view.get_children() + for category_expander in get_widget_children(self.category_view) if category_expander.get_label() in effect_info.categories] all_effect_listboxes.append(self.search_view) # Find and sync state in other listboxes for listbox in all_effect_listboxes: - for row in listbox.get_children(): + for row in get_listbox_children(listbox): effect_box = row.get_child().get_child() if effect == effect_box.effect_name: - fav_button = effect_box.get_children()[2] + fav_button = effect_box.get_last_child() # Sync the state with the clicked button self._set_fav_button_state(fav_button, clicked_button.active) @@ -635,7 +637,7 @@ class EffectListWidget(Gtk.Box, Loggable): def _search_filter(self, row): """Filters search_view to show search results.""" effect_box = row.get_child().get_child() - label = effect_box.get_children()[1] + label = get_widget_children(effect_box)[1] label_text = label.get_text().lower() search_key = self.search_entry.get_text().lower() @@ -658,7 +660,7 @@ class EffectListWidget(Gtk.Box, Loggable): # It's already visible, no need to switch to it. return - for child_view in self.main_view.get_children(): + for child_view in get_widget_children(self.main_view): child_view.props.visible = child_view == next_view @@ -708,7 +710,7 @@ class EffectsPopover(Gtk.Popover, Loggable): def _search_filter(self, row): effect_box = row.get_child().get_child() - label = effect_box.get_children()[0] + label = effect_box.get_first_child() label_text = label.get_text().lower() search_key = self.search_entry.get_text().lower() @@ -785,7 +787,7 @@ class EffectsPropertiesManager(GObject.Object, Loggable): def _post_configuration(self, effect, effect_set_ui): effect_name = effect.get_property("bin-description") if 'aspectratiocrop' in effect.get_property("bin-description"): - for widget in effect_set_ui.get_children()[0].get_children(): + for widget in get_widget_children(effect_set_ui.get_first_child()): if isinstance(widget, FractionWidget): widget.add_presets(["4:3", "5:4", "9:3", "16:9", "16:10"]) else: diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 49da93546..7f7a96e41 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -33,6 +33,7 @@ from pitivi.project import Project from pitivi.utils.ui import beautify_last_updated_timestamp from pitivi.utils.ui import beautify_project_path from pitivi.utils.ui import BinWithNaturalWidth +from pitivi.utils.ui import get_listbox_children from pitivi.utils.ui import GREETER_PERSPECTIVE_CSS from pitivi.utils.ui import PADDING from pitivi.utils.ui import SPACING @@ -170,7 +171,7 @@ class GreeterPerspective(Perspective): self.__selected_projects = [] # Clear the currently displayed list of recent projects. - for child in self.__recent_projects_listbox.get_children(): + while child := self.__recent_projects_listbox.get_row_at_index(0): self.__recent_projects_listbox.remove(child) recent_items = [item for item in self.app.recent_manager.get_items() @@ -192,9 +193,8 @@ class GreeterPerspective(Perspective): child = self.__welcome_vbox self.__update_headerbar(welcome=True) - children = self.__topvbox.get_children() - if children: - current_child = children[0] + current_child = self.__topvbox.get_first_child() + if current_child: if current_child == child: child = None else: @@ -390,7 +390,7 @@ class GreeterPerspective(Perspective): search_hit = False search_text = search_entry.get_text().lower() - for recent_project_item in self.__recent_projects_listbox.get_children(): + for recent_project_item in get_listbox_children(self.__recent_projects_listbox): if search_text in recent_project_item.name.lower(): recent_project_item.show() search_hit = True @@ -415,7 +415,7 @@ class GreeterPerspective(Perspective): self.__update_headerbar(selection=True) self.__search_entry.hide() self.__actionbar.show() - for child in self.__recent_projects_listbox.get_children(): + for child in get_listbox_children(self.__recent_projects_listbox): child.select_button.show() def __cancel_clicked_cb(self, unused_button): diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index b3b52e15e..2ad0086f7 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -57,6 +57,7 @@ from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import CURSORS from pitivi.utils.ui import DRAG_CURSOR from pitivi.utils.ui import EFFECT_TARGET_ENTRY +from pitivi.utils.ui import get_widget_children from pitivi.utils.ui import NORMAL_CURSOR from pitivi.utils.ui import set_state_flags_recurse @@ -1472,7 +1473,7 @@ class FullClip(Clip, Zoomable): layer.move(self, x, y) self.set_size_request(width, height) - elements = self._elements_container.get_children() + elements = get_widget_children(self._elements_container) for child in elements: child.set_size(width, height / len(elements)) diff --git a/pitivi/timeline/markers.py b/pitivi/timeline/markers.py index 3850a4acb..0f0c8b05f 100644 --- a/pitivi/timeline/markers.py +++ b/pitivi/timeline/markers.py @@ -25,6 +25,7 @@ from gi.repository import Gtk from pitivi.configure import get_ui_dir from pitivi.utils.loggable import Loggable from pitivi.utils.timeline import Zoomable +from pitivi.utils.ui import get_widget_children TIMELINE_MARKER_SIZE = 10 CLIP_MARKER_HEIGHT = 12 @@ -177,7 +178,7 @@ class MarkersBox(Gtk.Box, Zoomable, Loggable): @markers_container.setter def markers_container(self, ges_markers_container): if self.__markers_container: - for marker in self.layout.get_children(): + while marker := self.layout.get_first_child(): self.layout.remove(marker) self.__markers_container.disconnect_by_func(self._marker_added_cb) self.__markers_container.disconnect_by_func(self._marker_removed_cb) @@ -228,7 +229,7 @@ class MarkersBox(Gtk.Box, Zoomable, Loggable): self._update_position() def _update_position(self): - for marker in self.layout.get_children(): + for marker in get_widget_children(self.layout): position = self.ns_to_pixel(marker.position) - self.offset - marker.width / 2 self.layout.move(marker, position, 0) diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py index 091e596b2..57aa37f38 100644 --- a/pitivi/timeline/previewers.py +++ b/pitivi/timeline/previewers.py @@ -47,6 +47,7 @@ from pitivi.utils.system import CPUUsageTracker from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import CLIP_BORDER_WIDTH from pitivi.utils.ui import EXPANDED_SIZE +from pitivi.utils.ui import get_widget_children from pitivi.utils.ui import MINI_LAYER_HEIGHT # Our C module optimizing waveforms rendering @@ -531,7 +532,7 @@ class ImagePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): else: opacity = 1.0 - for thumb in self.get_children(): + for thumb in get_widget_children(self): thumb.props.opacity = opacity def start_generation(self): @@ -865,7 +866,7 @@ class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable): else: opacity = 1.0 - for thumb in self.get_children(): + for thumb in get_widget_children(self): thumb.props.opacity = opacity def refresh(self): diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index f73e8302f..0b9d61f6d 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -712,7 +712,7 @@ class CoverObjectPopover(Gtk.Popover, Loggable): """Updates the list of not yet covered objects.""" self.object_manager = ObjectManager(self.clip.asset) - for row in self.listbox.get_children(): + while row := self.listbox.get_row_at_index(0): self.listbox.remove(row) # Check which tracked objects have already been covered. diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index 1c589aaa1..150fc8a07 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -883,7 +883,7 @@ def set_state_flags_recurse(widget, state_flags, are_set, ignored_classes=()): widget.unset_state_flags(state_flags) if isinstance(widget, Gtk.Container): - for child in widget.get_children(): + for child in get_widget_children(widget): set_state_flags_recurse(child, state_flags, are_set, ignored_classes) @@ -904,6 +904,26 @@ def disable_scroll(widget): widget.connect("scroll-event", disable_scroll_event_cb) +def get_listbox_children(listbox): + index = 0 + child_list = [] + while child := listbox.get_row_at_index(index): + child_list.append(child) + index += 1 + return child_list + + +# ToDo: Can be further optimised and use Yield +def get_widget_children(widget, filter_func=lambda child: True): + child = widget.get_first_child() + child_list = [] + while child: + if filter_func(child): + child_list.append(child) + child = child.get_next_sibling() + return child_list + + AUDIO_CHANNELS = create_model((str, int), [(format_audiochannels(ch), ch) for ch in (8, 6, 4, 2, 1)]) diff --git a/tests/common.py b/tests/common.py index 3bf4ae69d..1f5d970c5 100644 --- a/tests/common.py +++ b/tests/common.py @@ -51,6 +51,7 @@ from pitivi.utils.proxy import ProxyingStrategy from pitivi.utils.proxy import ProxyManager from pitivi.utils.timeline import Selected from pitivi.utils.timeline import Zoomable +from pitivi.utils.ui import get_widget_children def handle_uncaught_exception_func(exctype, value, trace): @@ -477,7 +478,7 @@ class TestCase(unittest.TestCase, Loggable): expect_selected) self.assertEqual(ges_clip.selected.selected, expect_selected) - for child in ges_clip.ui.get_children(): + for child in get_widget_children(ges_clip.ui): if not hasattr(child, "selected"): continue @@ -525,12 +526,12 @@ class TestCase(unittest.TestCase, Loggable): # Check the positions of the Layer widgets. positions = [layers_vbox.child_get_property(ges_layer.ui, "position") for ges_layer in ges_layers] - self.assertListEqual(positions, expected_positions, layers_vbox.get_children()) + self.assertListEqual(positions, expected_positions, get_widget_children(layers_vbox)) # Check the positions of the MiniLayer widgets. positions = [mini_layers_vbox.child_get_property(ges_layer.mini_ui, "position") for ges_layer in ges_layers] - self.assertListEqual(positions, expected_positions, mini_layers_vbox.get_children()) + self.assertListEqual(positions, expected_positions, get_widget_children(mini_layers_vbox)) # Check the positions of the LayerControl widgets. controls_vbox = timeline._layers_controls_vbox diff --git a/tests/test_medialibrary.py b/tests/test_medialibrary.py index dfd645db2..6ffe50035 100644 --- a/tests/test_medialibrary.py +++ b/tests/test_medialibrary.py @@ -33,6 +33,7 @@ from pitivi.project import ProjectManager from pitivi.utils.misc import ASSET_DURATION_META from pitivi.utils.misc import asset_get_duration from pitivi.utils.proxy import ProxyingStrategy +from pitivi.utils.ui import get_widget_children from pitivi.utils.validate import create_event from tests import common @@ -541,12 +542,12 @@ class TestTaggingAssets(BaseTestMediaLibrary): def get_tags_list(self): box = self.medialibrary.tags_popover.get_child() - popover_widgets = box.get_children() + popover_widgets = get_widget_children(box) return popover_widgets[1] def assert_tags_popover(self, tags_state): box = self.medialibrary.tags_popover.get_child() - popover_widgets = box.get_children() + popover_widgets = get_widget_children(box) tags_list = popover_widgets[1] for row_widget in tags_list: diff --git a/tests/test_trackerperspective.py b/tests/test_trackerperspective.py index 2a0af20a6..2d7246a08 100644 --- a/tests/test_trackerperspective.py +++ b/tests/test_trackerperspective.py @@ -22,6 +22,7 @@ from gi.repository import GES from pitivi.check import MISSING_SOFT_DEPS from pitivi.trackerperspective import ObjectManager +from pitivi.utils.ui import get_listbox_children from tests import common @@ -39,7 +40,7 @@ class TestCoverObjectPopover(common.TestCase): expander.cover_object_button.clicked() self.assertTrue(expander.cover_popover.props.visible) # Only one row containing the Track Objects button should exist. - self.assertEqual(len(expander.cover_popover.listbox.get_children()), 1) + self.assertEqual(len(get_listbox_children(expander.cover_popover.listbox)), 1) expander.cover_object_button.clicked() self.assertFalse(expander.cover_popover.props.visible) @@ -54,7 +55,7 @@ class TestCoverObjectPopover(common.TestCase): expander.cover_object_button.clicked() self.assertTrue(expander.cover_popover.props.visible) # Two rows for two object and one for Track Objects. - self.assertEqual(len(expander.cover_popover.listbox.get_children()), 3) + self.assertEqual(len(get_listbox_children(expander.cover_popover.listbox)), 3) self.assertEqual(len(clip.get_top_effects()), 0) expander.cover_popover.listbox.get_row_at_index(0).emit("activate") @@ -64,7 +65,7 @@ class TestCoverObjectPopover(common.TestCase): expander.cover_object_button.clicked() self.assertTrue(expander.cover_popover.props.visible) # One row for the uncovered object and one for the Track Objects button. - self.assertEqual(len(expander.cover_popover.listbox.get_children()), 2) + self.assertEqual(len(get_listbox_children(expander.cover_popover.listbox)), 2) class TestObjectManager(common.TestCase): -- GitLab From f87accf60748ce51b100d8617c94eb772121b61f Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Tue, 23 Aug 2022 22:29:37 +0530 Subject: [PATCH 051/132] Replace deprecated delete-event --- pitivi/mainwindow.py | 4 ++-- pitivi/render.py | 6 +++--- pitivi/viewer/viewer.py | 4 ++-- plugins/console/console.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index b225ebba6..936e613eb 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -156,7 +156,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): self.check_screen_constraints() self.connect("configure-event", self.__configure_cb) - self.connect("delete-event", self.__delete_cb) + self.connect("close_request", self.__delete_cb) def __initial_placement_cb(self, x, y, width, height): self.__placed = True @@ -243,7 +243,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): self.app.settings.mainWindowWidth = size.width self.app.settings.mainWindowHeight = size.height - def __delete_cb(self, unused_widget, unused_event): + def __delete_cb(self, unused_event): self.app.settings.mainWindowHPanePosition = self.editor.secondhpaned.get_position() self.app.settings.mainWindowMainHPanePosition = self.editor.mainhpaned.get_position() self.app.settings.mainWindowVPanePosition = self.editor.toplevel_widget.get_position() diff --git a/pitivi/render.py b/pitivi/render.py index 4ce818248..72f97b8ec 100644 --- a/pitivi/render.py +++ b/pitivi/render.py @@ -740,7 +740,7 @@ class RenderingProgressDialog(GObject.Object): self._filesize_est_label.show() self._filesize_est_value_label.show() - def _delete_event_cb(self, unused_dialog_widget, unused_event): + def _close_request_cb(self, unused_event): """Stops the rendering.""" # The user closed the window by pressing Escape. self.emit("cancel") @@ -832,7 +832,7 @@ class RenderDialog(Loggable): self._display_render_settings() - self.window.connect("delete-event", self._delete_event_cb) + self.window.connect("close_request", self._close_request_cb) self.project.connect("video-size-changed", self._project_video_size_changed_cb) self.presets_manager.connect("profile-updated", self._presets_manager_profile_updated_cb) @@ -1539,7 +1539,7 @@ class RenderDialog(Loggable): self.project.disconnect_by_func(self._rendering_settings_changed_cb) self.destroy() - def _delete_event_cb(self, unused_window, unused_event): + def _close_request_cb(self, unused_event): self.debug("Render dialog is being deleted") self.destroy() diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index b7439a7e1..e83622a2f 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -218,7 +218,7 @@ class ViewerContainer(Gtk.Box, Loggable): if active: self.emit("activate-playback-controls", True) - def _external_window_delete_cb(self, unused_window, unused_event): + def _external_window_close_cb(self, unused_event): self.dock() return True @@ -238,7 +238,7 @@ class ViewerContainer(Gtk.Box, Loggable): vbox.set_spacing(SPACING) self.external_window.set_child(vbox) self.external_window.connect( - "delete-event", self._external_window_delete_cb) + "close_request", self._external_window_close_cb) self.external_window.connect( "configure-event", self._external_window_configure_cb) self.external_vbox = vbox diff --git a/plugins/console/console.py b/plugins/console/console.py index 792e1abe7..d6e8977cc 100644 --- a/plugins/console/console.py +++ b/plugins/console/console.py @@ -186,7 +186,7 @@ class Console(GObject.GObject, Peas.Activatable): self.window.set_default_size(600, 400) self.window.set_title(_("Pitivi Console")) - self.window.connect("delete-event", self.__delete_event_cb) + self.window.connect("close_request", self.__close_request_cb) self.window.set_child(self.terminal) def _create_welcome_message(self, namespace): @@ -243,5 +243,5 @@ class Console(GObject.GObject, Peas.Activatable): self.window.hide() return True - def __delete_event_cb(self, unused_widget, unused_data): + def __close_request_cb(self, unused_data): return self.window.hide_on_delete() -- GitLab From c61657510b7ea029f2dca52cfbdf6c3187ef843c Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Tue, 23 Aug 2022 23:32:58 +0530 Subject: [PATCH 052/132] Replace deprecated get_size --- pitivi/editorperspective.py | 5 +++-- pitivi/mainwindow.py | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 216f65e2b..3c3d9e914 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -270,7 +270,7 @@ class EditorPerspective(Perspective, Loggable): self.toplevel_widget.set_position(self.settings.mainWindowVPanePosition) def _set_default_positions(self): - window_width = self.app.gui.get_size()[0] + window_width = self.app.gui.get_width() if self.settings.mainWindowHPanePosition is None: self.settings.mainWindowHPanePosition = window_width / 3 if self.settings.mainWindowMainHPanePosition is None: @@ -864,7 +864,8 @@ class PreviewAssetWindow(Gtk.Window): video = video_streams[0] img_width = video.get_natural_width() img_height = video.get_natural_height() - mainwindow_width, mainwindow_height = self.app.gui.get_size() + mainwindow_width = self.app.gui.get_width() + mainwindow_height = self.app.gui.get_height() max_width = 0.85 * mainwindow_width max_height = 0.85 * mainwindow_height diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 936e613eb..87c6b1645 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -239,9 +239,10 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): self.app.settings.mainWindowX = position.root_x self.app.settings.mainWindowY = position.root_y - size = self.get_size() - self.app.settings.mainWindowWidth = size.width - self.app.settings.mainWindowHeight = size.height + size_width = self.get_width() + size_height = self.get_height() + self.app.settings.mainWindowWidth = size_width + self.app.settings.mainWindowHeight = size_height def __delete_cb(self, unused_event): self.app.settings.mainWindowHPanePosition = self.editor.secondhpaned.get_position() -- GitLab From f95f27678964f7fde00835b6f415c77fd4562152 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 25 Aug 2022 00:37:04 +0530 Subject: [PATCH 053/132] Drop use of deprecated get_accessible() --- pitivi/editorperspective.py | 20 ++++++++++---------- pitivi/medialibrary.py | 2 +- pitivi/project.py | 4 ++-- pitivi/timeline/elements.py | 2 +- pitivi/timeline/timeline.py | 4 ++-- pitivi/viewer/viewer.py | 14 +++++++------- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 3c3d9e914..f29c31157 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -252,15 +252,15 @@ class EditorPerspective(Perspective, Loggable): # Identify widgets for AT-SPI, making our test suite easier to develop # These will show up in sniff, accerciser, etc. - self.headerbar.get_accessible().set_name("editor_headerbar") - self.menu_button.get_accessible().set_name("main menu button") - self.toplevel_widget.get_accessible().set_name("contents") - self.mainhpaned.get_accessible().set_name("upper half") - self.secondhpaned.get_accessible().set_name("tabs") - self.main_tabs.get_accessible().set_name("primary tabs") - self.context_tabs.get_accessible().set_name("secondary tabs") - self.viewer.get_accessible().set_name("viewer") - self.timeline_ui.get_accessible().set_name("timeline area") + self.headerbar.set_name("editor_headerbar") + self.menu_button.set_name("main menu button") + self.toplevel_widget.set_name("contents") + self.mainhpaned.set_name("upper half") + self.secondhpaned.set_name("tabs") + self.main_tabs.set_name("primary tabs") + self.context_tabs.set_name("secondary tabs") + self.viewer.set_name("viewer") + self.timeline_ui.set_name("timeline area") # Restore settings for position and visibility. if self.settings.mainWindowHPanePosition is None: @@ -546,7 +546,7 @@ class EditorPerspective(Perspective, Loggable): save, Gtk.ResponseType.YES) dialog.set_default_response(Gtk.ResponseType.CANCEL) - dialog.get_accessible().set_name("unsaved changes dialog") + dialog.set_name("unsaved changes dialog") reject_btn.add_css_class("destructive-action") primary = _("Save changes to the current project before closing?") diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 14118763d..a0b431b69 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -573,7 +573,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.scrollwin.set_hexpand(True) self.scrollwin.set_policy( Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) - self.scrollwin.get_accessible().set_name( + self.scrollwin.set_name( "media_flowbox_scrollwindow") self.store = Gio.ListStore() diff --git a/pitivi/project.py b/pitivi/project.py index bf062aa67..f108303aa 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -199,7 +199,7 @@ class ProjectManager(GObject.Object, Loggable): dialog.set_default_response(1) # Default to "Save as" dialog.set_icon_name("pitivi") dialog.set_modal(True) - dialog.get_accessible().set_name("pitivi died") + dialog.set_name("pitivi died") primary = Gtk.Label() primary.set_wrap(True) @@ -301,7 +301,7 @@ class ProjectManager(GObject.Object, Loggable): dialog.set_icon_name("pitivi") dialog.set_modal(True) dialog.set_default_response(Gtk.ResponseType.YES) - dialog.get_accessible().set_name("restore from backup dialog") + dialog.set_name("restore from backup dialog") primary = Gtk.Label() primary.set_wrap(True) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 2ad0086f7..4c4506087 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -1176,7 +1176,7 @@ class Clip(Gtk.Box, Loggable): name = ges_clip.get_name() self.set_name(name) - self.get_accessible().set_name(name) + self.set_name(name) self._elements_container = None self.left_handle = None diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 84268cb08..b74fe2b2e 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -428,7 +428,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.add_css_class("Timeline") self.props.expand = True - self.get_accessible().set_name("timeline canvas") + self.set_name("timeline canvas") assert self.get_has_window() # A lot of operations go through the handlers of these events. @@ -1863,7 +1863,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): builder = Gtk.Builder() builder.add_from_file(os.path.join(get_ui_dir(), "timelinetoolbar.ui")) self.toolbar = builder.get_object("timeline_box") - self.toolbar.get_accessible().set_name("timeline box") + self.toolbar.set_name("timeline box") self.gapless_button = builder.get_object("gapless_button") self.gapless_button.set_active(self._settings.timelineAutoRipple) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index e83622a2f..1407299dc 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -371,13 +371,13 @@ class ViewerContainer(Gtk.Box, Loggable): # Identify widgets for AT-SPI, making our test suite easier to develop # These will show up in sniff, accerciser, etc. - self.start_button.get_accessible().set_name("start_button") - self.back_button.get_accessible().set_name("back_button") - self.playpause_button.get_accessible().set_name("playpause_button") - self.forward_button.get_accessible().set_name("forward_button") - self.end_button.get_accessible().set_name("end_button") - self.timecode_entry.get_accessible().set_name("timecode_entry") - self.undock_button.get_accessible().set_name("undock_button") + self.start_button.set_name("start_button") + self.back_button.set_name("back_button") + self.playpause_button.set_name("playpause_button") + self.forward_button.set_name("forward_button") + self.end_button.set_name("end_button") + self.timecode_entry.set_name("timecode_entry") + self.undock_button.set_name("undock_button") self.buttons_container = bbox self.external_vbox.show() -- GitLab From cdcbc778d0c161642f1030618ccb0f49d8f91b83 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 25 Aug 2022 00:49:54 +0530 Subject: [PATCH 054/132] Drop use of response signal in AboutWindow --- pitivi/dialogs/about.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pitivi/dialogs/about.py b/pitivi/dialogs/about.py index 449dd3126..6bd86fca9 100644 --- a/pitivi/dialogs/about.py +++ b/pitivi/dialogs/about.py @@ -80,9 +80,4 @@ class AboutDialog(Gtk.AboutDialog): self.set_documenters(documenters) self.set_license_type(Gtk.License.LGPL_2_1) self.set_logo_icon_name("org.pitivi.Pitivi") - self.connect("response", self.__about_response_cb) self.set_transient_for(app.gui) - - @staticmethod - def __about_response_cb(dialog, unused_response): - dialog.destroy() -- GitLab From faca2e22cb360d5322100453444d00bc3d0b3f71 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 25 Aug 2022 01:03:44 +0530 Subject: [PATCH 055/132] Drop use of deprecated set_alignment --- pitivi/dialogs/prefs.py | 2 +- pitivi/project.py | 4 ++-- pitivi/utils/widgets.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 5bead6ca4..efb4dbf55 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -249,7 +249,7 @@ class PreferencesDialog(Loggable): box = Gtk.Box() label_widget = Gtk.Label.new(label) - label_widget.set_alignment(0.0, 0.5) + label_widget.set_yalign(0.5) label_widget.props.margin_end = PADDING * 3 label_widget.props.margin_top = PADDING * 2 label_widget.props.margin_bottom = PADDING * 2 diff --git a/pitivi/project.py b/pitivi/project.py index f108303aa..d09da000d 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -204,7 +204,7 @@ class ProjectManager(GObject.Object, Loggable): primary = Gtk.Label() primary.set_wrap(True) primary.set_use_markup(True) - primary.set_alignment(0, 0.5) + primary.set_yalign(0.5) primary.props.label = message primary.set_hexpand(True) primary.set_halign(Gtk.Align.FILL) @@ -306,7 +306,7 @@ class ProjectManager(GObject.Object, Loggable): primary = Gtk.Label() primary.set_wrap(True) primary.set_use_markup(True) - primary.set_alignment(0, 0.5) + primary.set_yalign(0.5) message = _("An autosaved version of your project file was found. " "It is %s newer than the saved project.\n\n" diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 2933a12b4..f47f4ef90 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -905,7 +905,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): widget = prop_widget label = Gtk.Label.new(prop.nick) - label.set_alignment(0.0, 0.5) + label.set_yalign(0.5) grid.attach(label, 0, y, 1, 1) grid.attach(widget, 1, y, 1, 1) if hasattr(prop, 'blurb'): -- GitLab From b71fd3f8b8faa283ece30a2b46433090418e234a Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 25 Aug 2022 01:31:32 +0530 Subject: [PATCH 056/132] Adapt to GtkCheckBox and GtkRadioButton changes --- data/ui/clipmediaprops.ui | 5 ----- data/ui/project_info.ui | 1 - data/ui/renderingdialog.ui | 13 +++++-------- data/ui/titleeditor.ui | 1 - pitivi/transitions.py | 4 ++-- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/data/ui/clipmediaprops.ui b/data/ui/clipmediaprops.ui index 77fcb237e..2187af6b8 100644 --- a/data/ui/clipmediaprops.ui +++ b/data/ui/clipmediaprops.ui @@ -74,7 +74,6 @@ True False start - True 0 0 @@ -88,7 +87,6 @@ True False start - True 0 1 @@ -102,7 +100,6 @@ True False start - True 0 2 @@ -186,7 +183,6 @@ True False start - True 0 1 @@ -200,7 +196,6 @@ True False start - True 0 0 diff --git a/data/ui/project_info.ui b/data/ui/project_info.ui index 4ca71c226..dd9901f0c 100644 --- a/data/ui/project_info.ui +++ b/data/ui/project_info.ui @@ -11,7 +11,6 @@ False False 12 - True fill diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index d4185e94a..be7963c33 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -251,7 +251,7 @@ start vertical - + Automatically render from proxy files True True @@ -261,11 +261,10 @@ This option is a good trade-off between quality of the rendered video and stability. start True - True - + Always render from proxy files True True @@ -273,11 +272,11 @@ This option is a good trade-off between quality of the rendered video and stabil Render all proxied clips from the proxy assets. There might be some quality loss during the rendering process. start True - True + automatically_use_proxies - + Never render from proxy files True True @@ -286,7 +285,7 @@ This option is a good trade-off between quality of the rendered video and stabil <i>Use at your own risk!</i> start True - True + automatically_use_proxies @@ -412,7 +411,6 @@ This option is a good trade-off between quality of the rendered video and stabil False start True - True @@ -567,7 +565,6 @@ This option is a good trade-off between quality of the rendered video and stabil False start True - True diff --git a/data/ui/titleeditor.ui b/data/ui/titleeditor.ui index d1fefb0f5..a13a5b420 100644 --- a/data/ui/titleeditor.ui +++ b/data/ui/titleeditor.ui @@ -153,7 +153,6 @@ True False 10 - True start diff --git a/pitivi/transitions.py b/pitivi/transitions.py index a5df72406..72ce08c21 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -77,12 +77,12 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.props_widgets.props.margin = PADDING self.props_widgets.props.column_spacing = SPACING - self.border_mode_normal = Gtk.RadioButton( + self.border_mode_normal = Gtk.CheckButton( group=None, label=_("Normal")) self.border_mode_normal.set_active(True) self.props_widgets.attach(self.border_mode_normal, 0, 0, 1, 1) - self.border_mode_loop = Gtk.RadioButton( + self.border_mode_loop = Gtk.CheckButton( group=self.border_mode_normal, label=_("Loop")) self.props_widgets.attach(self.border_mode_loop, 0, 1, 1, 1) -- GitLab From dc7c8b93d6b4d8324adbf2717122dc0726366d32 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 25 Aug 2022 17:33:59 +0530 Subject: [PATCH 057/132] Update mainwindow resize and size functions --- pitivi/mainwindow.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 87c6b1645..0a43080df 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -34,12 +34,6 @@ from pitivi.utils.loggable import Loggable from pitivi.utils.misc import show_user_manual -GlobalSettings.add_config_option('mainWindowX', - section="main-window", - key="X", default=0, type_=int) -GlobalSettings.add_config_option('mainWindowY', - section="main-window", - key="Y", default=0, type_=int) GlobalSettings.add_config_option('mainWindowWidth', section="main-window", key="width", default=-1, type_=int) @@ -158,10 +152,9 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): self.connect("configure-event", self.__configure_cb) self.connect("close_request", self.__delete_cb) - def __initial_placement_cb(self, x, y, width, height): + def __initial_placement_cb(self, width, height): self.__placed = True - self.resize(width, height) - self.move(x, y) + self.set_default_size(width, height) if self.__wanted_perspective: self.show_perspective(self.__wanted_perspective) self.__wanted_perspective = None @@ -234,11 +227,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): PreferencesDialog(self.app).run() def __configure_cb(self, unused_widget, unused_event): - """Saves the main window position and size.""" - position = self.get_position() - self.app.settings.mainWindowX = position.root_x - self.app.settings.mainWindowY = position.root_y - + """Saves the main window size.""" size_width = self.get_width() size_height = self.get_height() self.app.settings.mainWindowWidth = size_width -- GitLab From e7d3ca0b0f8caa805fb0a96d9e5fbdc1c7eb7a08 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 27 Aug 2022 00:19:30 +0530 Subject: [PATCH 058/132] Update Open project GtkFileChooser --- pitivi/dialogs/browseprojects.py | 16 +++------------- pitivi/greeterperspective.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/pitivi/dialogs/browseprojects.py b/pitivi/dialogs/browseprojects.py index e86c8879e..4b01c28c8 100644 --- a/pitivi/dialogs/browseprojects.py +++ b/pitivi/dialogs/browseprojects.py @@ -18,6 +18,7 @@ from gettext import gettext as _ from gi.repository import GES +from gi.repository import Gio from gi.repository import Gtk @@ -39,7 +40,8 @@ class BrowseProjectsDialog(Gtk.FileChooserDialog): _("Open"), Gtk.ResponseType.OK) self.set_default_response(Gtk.ResponseType.OK) self.set_select_multiple(False) - self.set_current_folder(app.settings.lastProjectFolder) + gfile = Gio.File.new_for_path(app.settings.lastProjectFolder) + self.set_current_folder(gfile) formatter_assets = GES.list_assets(GES.Formatter) formatter_assets.sort( key=lambda x: - x.get_meta(GES.META_FORMATTER_RANK)) @@ -51,15 +53,3 @@ class BrowseProjectsDialog(Gtk.FileChooserDialog): extension = format_.get_meta(GES.META_FORMATTER_EXTENSION) file_filter.add_pattern("*{}".format(extension)) self.add_filter(file_filter) - default = Gtk.FileFilter() - default.set_name(_("All supported formats")) - default.add_custom(Gtk.FileFilterFlags.URI, self.__can_load_uri, None) - self.add_filter(default) - - # pylint: disable=bare-except - @staticmethod - def __can_load_uri(filterinfo, unused_uri): - try: - return GES.Formatter.can_load_uri(filterinfo.uri) - except: - return False diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 7f7a96e41..f15a432c3 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -336,11 +336,15 @@ class GreeterPerspective(Perspective): def __open_project_cb(self, unused_action, unused_param): dialog = BrowseProjectsDialog(self.app) - response = dialog.run() - uri = dialog.get_uri() - dialog.destroy() - if response == Gtk.ResponseType.OK: + dialog.connect("response", self._browse_projects_dialog_cb) + dialog.show() + + def _browse_projects_dialog_cb(self, dialog, response_id): + gfile = dialog.get_file() + uri = gfile.get_uri() + if response_id == Gtk.ResponseType.OK: self.app.project_manager.load_project(uri) + dialog.close() def __app_version_info_received_cb(self, app, unused_version_information): """Handles new version info.""" -- GitLab From e0392048fb6e3723bd288c76d31311b168f6beb5 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 27 Aug 2022 14:31:35 +0530 Subject: [PATCH 059/132] Drop use of dialog.run --- data/ui/preferences.ui | 1 + pitivi/dialogs/clipmediaprops.py | 2 +- pitivi/dialogs/prefs.py | 2 +- pitivi/dialogs/projectsettings.py | 3 ++- pitivi/editorperspective.py | 10 +++++++--- pitivi/mainwindow.py | 11 ++++++++--- pitivi/mediafilespreviewer.py | 7 +++++-- pitivi/medialibrary.py | 2 +- pitivi/project.py | 9 ++++++--- pitivi/render.py | 17 ++++++++++++----- pitivi/utils/misc.py | 12 ++++++++---- 11 files changed, 52 insertions(+), 24 deletions(-) diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index 96b774b66..88e1cef78 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -4,6 +4,7 @@ False Preferences + True False dialog diff --git a/pitivi/dialogs/clipmediaprops.py b/pitivi/dialogs/clipmediaprops.py index 576d9977c..54314b6a4 100644 --- a/pitivi/dialogs/clipmediaprops.py +++ b/pitivi/dialogs/clipmediaprops.py @@ -128,7 +128,7 @@ class ClipMediaPropsDialog: self.dialog.connect("key-press-event", self._key_press_cb) self.dialog.connect("response", self.__response_cb) - self.dialog.run() + self.dialog.show() def _apply(self): """Applies the widgets values to the project.""" diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index efb4dbf55..d914def5e 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -101,7 +101,7 @@ class PreferencesDialog(Loggable): def run(self): """Runs the dialog.""" PreferencesDialog._instance = self - self.dialog.run() + self.dialog.show() PreferencesDialog._instance = None def __setup_css(self): diff --git a/pitivi/dialogs/projectsettings.py b/pitivi/dialogs/projectsettings.py index fab634a0a..c8c615117 100644 --- a/pitivi/dialogs/projectsettings.py +++ b/pitivi/dialogs/projectsettings.py @@ -214,7 +214,8 @@ class ProjectSettingsDialog: def _proxy_settings_label_cb(self, unused_widget, unused_parm): prefs_dialog = PreferencesDialog(self.app) prefs_dialog.stack.set_visible_child_name("_proxies") - prefs_dialog.run() + prefs_dialog.set_modal(True) + prefs_dialog.show() def update_scaled_proxy_width(self): height = int(self.scaled_proxy_height_spin.get_value()) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index f29c31157..7a01da1f3 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -464,7 +464,8 @@ class EditorPerspective(Perspective, Loggable): def show_project_settings_dialog(self): project = self.app.project_manager.current_project dialog = ProjectSettingsDialog(self.app.gui, project, self.app) - dialog.window.run() + dialog.window.set_modal(True) + dialog.window.show() self.update_title() # Project management callbacks @@ -511,8 +512,11 @@ class EditorPerspective(Perspective, Loggable): dialog.set_property("secondary-use-markup", True) dialog.set_property("secondary-text", unquote(str(exception))) dialog.set_transient_for(self.app.gui) - dialog.run() - dialog.destroy() + + def dialog_response_cb(dialog, response_id): + dialog.destroy() + dialog.connect("response", dialog_response_cb) + dialog.show() self.error("failed to save project") def _project_manager_project_saved_cb(self, unused_project_manager, unused_project, unused_uri): diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 0a43080df..849cad946 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -224,7 +224,9 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): self.__perspective.menu_button.set_active(active) def __preferences_cb(self, unused_action, unused_param): - PreferencesDialog(self.app).run() + dialog = PreferencesDialog(self.app) + dialog.set_modal(True) + dialog.show() def __configure_cb(self, unused_widget, unused_event): """Saves the main window size.""" @@ -255,10 +257,13 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): dialog.set_property("secondary-use-markup", True) dialog.set_property("secondary-text", unquote(str(reason))) dialog.set_transient_for(self) - dialog.run() - dialog.destroy() + dialog.connect("response", self._new_project_failed_dialog_cb) + dialog.show() self.show_perspective(self.greeter) + def _new_project_failed_dialog_cb(self, dialog, response_id): + dialog.destroy() + def __project_closed_cb(self, unused_project_manager, unused_project): self.show_perspective(self.greeter) diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index 6f4d8d3b9..e76ddcfe7 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -461,8 +461,11 @@ class PreviewWidget(Gtk.Grid, Loggable): text=self.error_message) dialog.set_icon_name("pitivi") dialog.set_title(_("Error while analyzing a file")) - dialog.run() - dialog.destroy() + + def dialog_response_cb(dialog, response_id): + dialog.destroy() + dialog.connect("response", dialog_response_cb) + dialog.show() def do_destroy(self): """Handles the destruction of the widget.""" diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index a0b431b69..393c77c34 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -1135,7 +1135,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): asset = assets[0] dialog = ClipMediaPropsDialog(self._project, asset) dialog.dialog.set_transient_for(self.app.gui) - dialog.run() + dialog.show() def __warning_infobar_cb(self, infobar, response_id): if response_id == Gtk.ResponseType.OK: diff --git a/pitivi/project.py b/pitivi/project.py index d09da000d..1d12c9bb6 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -237,12 +237,15 @@ class ProjectManager(GObject.Object, Loggable): content_area.prepend(hbox) content_area.set_spacing(SPACING * 2) - response = dialog.run() + dialog.connect("response", self._project_pipeline_died_dialog_cb) + dialog.show() + + def _project_pipeline_died_dialog_cb(self, dialog, response_id): dialog.destroy() - if response == 1: + if response_id == 1: self.app.gui.editor.save_project_as() - elif response == 2: + elif response_id == 2: self.app.gui.editor.save_project() self.app.shutdown() diff --git a/pitivi/render.py b/pitivi/render.py index 72f97b8ec..9d07a343a 100644 --- a/pitivi/render.py +++ b/pitivi/render.py @@ -1328,8 +1328,11 @@ class RenderDialog(Loggable): text=primary_message) dialog.set_property("secondary-text", secondary_message) dialog.set_property("secondary-use-markup", True) - dialog.run() - dialog.destroy() + + def dialog_response_cb(dialog, response_id): + dialog.destroy() + dialog.connect("response", dialog_response_cb) + dialog.show() def start_action(self): """Starts the render process.""" @@ -1495,13 +1498,16 @@ class RenderDialog(Loggable): shortcut = os.path.dirname(self.project.uri) chooser.add_shortcut_folder_uri(shortcut) - response = chooser.run() + chooser.connect("response", self._select_file_dialog_cb, file_filter) + chooser.show() + + def _select_file_dialog_cb(self, chooser, response, file_filter): if response == Gtk.ResponseType.DELETE_EVENT: # This happens because Gtk.FileChooserNative is confused because we # added a filter but since it's ignored it complains there is none. # Try again without the filter. chooser.remove_filter(file_filter) - response = chooser.run() + chooser.show() if response == Gtk.ResponseType.ACCEPT: self.app.settings.lastExportFolder = chooser.get_current_folder() @@ -1679,7 +1685,8 @@ class RenderDialog(Loggable): def _project_settings_button_clicked_cb(self, unused_button): dialog = ProjectSettingsDialog(self.window, self.project, self.app) - dialog.window.run() + dialog.window.set_modal(True) + dialog.window.show() self._display_settings() def _audio_output_checkbutton_toggled_cb(self, unused_audio): diff --git a/pitivi/utils/misc.py b/pitivi/utils/misc.py index 36cfd03cf..c663b43cc 100644 --- a/pitivi/utils/misc.py +++ b/pitivi/utils/misc.py @@ -282,8 +282,8 @@ def show_user_manual(page=None): " Make sure to have either the `yelp` GNOME" " documentation viewer or a web browser" " installed")) - dialog.run() - dialog.destroy() + dialog.connect("response", _dialog_response_cb) + dialog.show() def unicode_error_dialog(): @@ -298,8 +298,8 @@ def unicode_error_dialog(): text=message) dialog.set_icon_name("pitivi") dialog.set_title(_("Error while decoding a string")) - dialog.run() - dialog.destroy() + dialog.connect("response", _dialog_response_cb) + dialog.show() def intersect(v1, v2): @@ -560,3 +560,7 @@ def is_pathname_valid(pathname: str) -> bool: # (e.g., a bug). Permit this exception to unwind the call stack. # # Did we mention this should be shipped with Python already? + + +def _dialog_response_cb(self, dialog, response): + dialog.close() -- GitLab From 0c08fcc5359bf31ecb1af58eccbebf6f0acf9c52 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 27 Aug 2022 14:51:10 +0530 Subject: [PATCH 060/132] Update greeter.ui to GTK4 --- data/ui/greeter.ui | 85 ++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 63 deletions(-) diff --git a/data/ui/greeter.ui b/data/ui/greeter.ui index 185809fee..ae8f0c763 100644 --- a/data/ui/greeter.ui +++ b/data/ui/greeter.ui @@ -1,17 +1,15 @@ + - True - False center 30 10 vertical - True - True + 1 center 32 35 @@ -20,26 +18,19 @@ recent_projects_labelbox - True - False - fill recent_projects_label - True - False start - Recent Projects + Recent Projects - True - False end 12 - True - Updated + 1 + Updated @@ -47,41 +38,27 @@ recent_projects_listbox - True - False - fill - True - False vertical - True - True - fill + 1 never - True - + 1 + - True - False - + - True - False vertical - True - False - fill - True + 1 - False + 0 16 @@ -96,7 +73,7 @@ - False + 0 6 @@ -113,69 +90,51 @@ - True - False vertical - fill - + - + - True - False end - True + 1 - Remove - True - True - True + Remove + 1 + 1 - True - False center - True + 1 vertical - + -- GitLab From 6f045181600eeb34185d808fe6526ccf048c4b41 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 27 Aug 2022 14:55:08 +0530 Subject: [PATCH 061/132] Update effectslibrary.ui to GTK4 --- data/ui/effectslibrary.ui | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/data/ui/effectslibrary.ui b/data/ui/effectslibrary.ui index 967d45330..f0536c38f 100644 --- a/data/ui/effectslibrary.ui +++ b/data/ui/effectslibrary.ui @@ -2,27 +2,25 @@ - True - False + 0 Favorites - True - True + 1 + 1 - True 5 - True - True - True - Search... + 1 + 1 + 1 + Search... -- GitLab From 2405f16bc2bb8c69351b038d83f7c0ad52071bb0 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 28 Aug 2022 21:17:19 +0530 Subject: [PATCH 062/132] Add signals to Builder --- pitivi/clip_properties/color.py | 2 +- pitivi/clip_properties/compositing.py | 2 +- pitivi/clip_properties/markers.py | 2 +- pitivi/clip_properties/title.py | 2 +- pitivi/dialogs/clipmediaprops.py | 2 +- pitivi/dialogs/filelisterrordialog.py | 2 +- pitivi/dialogs/prefs.py | 2 +- pitivi/dialogs/projectsettings.py | 2 +- pitivi/effects.py | 2 +- pitivi/medialibrary.py | 2 +- pitivi/render.py | 4 ++-- pitivi/utils/widgets.py | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pitivi/clip_properties/color.py b/pitivi/clip_properties/color.py index eb31537f2..c466f1bdc 100644 --- a/pitivi/clip_properties/color.py +++ b/pitivi/clip_properties/color.py @@ -56,7 +56,7 @@ class ColorProperties(Gtk.Expander, Loggable): self._create_ui() def _create_ui(self): - self.builder = Gtk.Builder() + self.builder = Gtk.Builder(self) self.builder.add_from_file(os.path.join(get_ui_dir(), "clipcolor.ui")) box = self.builder.get_object("color_box") diff --git a/pitivi/clip_properties/compositing.py b/pitivi/clip_properties/compositing.py index 435af8069..e2aec4f67 100644 --- a/pitivi/clip_properties/compositing.py +++ b/pitivi/clip_properties/compositing.py @@ -56,7 +56,7 @@ class CompositingProperties(Gtk.Expander, Loggable): self.set_expanded(True) self.set_label(_("Compositing")) - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "clipcompositing.ui")) compositing_box = builder.get_object("compositing_box") diff --git a/pitivi/clip_properties/markers.py b/pitivi/clip_properties/markers.py index 25d5dd254..9a40770f1 100644 --- a/pitivi/clip_properties/markers.py +++ b/pitivi/clip_properties/markers.py @@ -201,7 +201,7 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): manager.snappable = active def _create_beat_detection_ui(self) -> Gtk.Box: - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "beatdetection.ui")) self._detect_button = builder.get_object("detect-button") diff --git a/pitivi/clip_properties/title.py b/pitivi/clip_properties/title.py index d6caf4c82..038ff1114 100644 --- a/pitivi/clip_properties/title.py +++ b/pitivi/clip_properties/title.py @@ -75,7 +75,7 @@ class TitleProperties(Gtk.Expander, Loggable): self._create_ui() def _create_ui(self): - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "titleeditor.ui")) # Create UI self.set_child(builder.get_object("box1")) diff --git a/pitivi/dialogs/clipmediaprops.py b/pitivi/dialogs/clipmediaprops.py index 54314b6a4..e2f15cbc9 100644 --- a/pitivi/dialogs/clipmediaprops.py +++ b/pitivi/dialogs/clipmediaprops.py @@ -46,7 +46,7 @@ class ClipMediaPropsDialog: self.has_video = False self.is_image = False - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "clipmediaprops.ui")) self.dialog = builder.get_object("Import Settings") # Checkbuttons (with their own labels) in the first table column: diff --git a/pitivi/dialogs/filelisterrordialog.py b/pitivi/dialogs/filelisterrordialog.py index 22c4a8b85..970daad6b 100644 --- a/pitivi/dialogs/filelisterrordialog.py +++ b/pitivi/dialogs/filelisterrordialog.py @@ -38,7 +38,7 @@ class FileListErrorDialog(GObject.Object, Loggable): def __init__(self, title, headline): GObject.Object.__init__(self) Loggable.__init__(self) - self.builder = Gtk.Builder() + self.builder = Gtk.Builder(self) self.builder.add_from_file(os.path.join(get_ui_dir(), "filelisterrordialog.ui")) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index d914def5e..8e5847c4f 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -79,7 +79,7 @@ class PreferencesDialog(Loggable): self.action_ids = {} # Identify the widgets we'll need - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "preferences.ui")) self.dialog = builder.get_object("dialog1") self.sidebar = builder.get_object("sidebar") diff --git a/pitivi/dialogs/projectsettings.py b/pitivi/dialogs/projectsettings.py index c8c615117..f58188fc9 100644 --- a/pitivi/dialogs/projectsettings.py +++ b/pitivi/dialogs/projectsettings.py @@ -54,7 +54,7 @@ class ProjectSettingsDialog: def _create_ui(self): """Initializes the static parts of the UI.""" - self.builder = Gtk.Builder() + self.builder = Gtk.Builder(self) self.builder.add_from_file( os.path.join(get_ui_dir(), "projectsettings.ui")) diff --git a/pitivi/effects.py b/pitivi/effects.py index bd4c5f855..de5eb7b95 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -392,7 +392,7 @@ class EffectListWidget(Gtk.Box, Loggable): os.path.join(get_pixmap_dir(), "star-solid.svg"), 15, 15) self.set_orientation(Gtk.Orientation.VERTICAL) - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "effectslibrary.ui")) toolbar = builder.get_object("effectslibrary_box") self.search_entry = builder.get_object("search_entry") diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 393c77c34..caa753f2f 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -538,7 +538,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self._last_suggested_tags: Set[str] = set() self.set_orientation(Gtk.Orientation.VERTICAL) - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file(os.path.join(get_ui_dir(), "medialibrary.ui")) self._welcome_infobar = builder.get_object("welcome_infobar") self._project_settings_infobar = Gtk.InfoBar() diff --git a/pitivi/render.py b/pitivi/render.py index 9d07a343a..45ba83bb6 100644 --- a/pitivi/render.py +++ b/pitivi/render.py @@ -687,7 +687,7 @@ class RenderingProgressDialog(GObject.Object): self.app = app self.main_render_dialog = parent - self.builder = Gtk.Builder() + self.builder = Gtk.Builder(self) self.builder.add_from_file( os.path.join(configure.get_ui_dir(), "renderingprogress.ui")) @@ -916,7 +916,7 @@ class RenderDialog(Loggable): return True def _create_ui(self): - builder = Gtk.Builder() + builder = Gtk.Builder(self) builder.add_from_file( os.path.join(configure.get_ui_dir(), "renderingdialog.ui")) diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index f47f4ef90..a61004099 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -1136,7 +1136,7 @@ class GstElementSettingsDialog(Loggable): self.properties = properties self.__caps = caps - self.builder = Gtk.Builder() + self.builder = Gtk.Builder(self) self.builder.add_from_file( os.path.join(get_ui_dir(), "elementsettingsdialog.ui")) self.ok_btn = self.builder.get_object("okbutton1") -- GitLab From 990f2ca4c672871135e0b56ae9bf8bd029d13d6f Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 1 Sep 2022 21:56:53 +0530 Subject: [PATCH 063/132] Implement EventControllers --- data/ui/renderingprogress.ui | 2 +- data/ui/trackerperspective.ui | 18 +++- pitivi/action_search_bar.py | 14 +-- pitivi/clip_properties/alignment.py | 18 ++-- pitivi/dialogs/clipmediaprops.py | 8 +- pitivi/editorperspective.py | 14 ++- pitivi/greeterperspective.py | 19 ++-- pitivi/mediafilespreviewer.py | 44 ++++---- pitivi/medialibrary.py | 28 ++--- pitivi/timeline/elements.py | 46 ++++---- pitivi/timeline/layer.py | 6 +- pitivi/timeline/timeline.py | 160 +++++++++++++++------------- pitivi/trackerperspective.py | 71 ++++++------ pitivi/utils/ui.py | 9 +- pitivi/utils/widgets.py | 41 ++++--- pitivi/viewer/viewer.py | 41 ++++--- plugins/console/widgets.py | 22 ++-- 17 files changed, 321 insertions(+), 240 deletions(-) diff --git a/data/ui/renderingprogress.ui b/data/ui/renderingprogress.ui index 33031b15c..8228b2bc5 100644 --- a/data/ui/renderingprogress.ui +++ b/data/ui/renderingprogress.ui @@ -9,7 +9,7 @@ center-on-parent 400 dialog - + True diff --git a/data/ui/trackerperspective.ui b/data/ui/trackerperspective.ui index c0af20126..e86d174b4 100644 --- a/data/ui/trackerperspective.ui +++ b/data/ui/trackerperspective.ui @@ -5,12 +5,20 @@ True False GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK - - + + + + + + - - - + + + + + + + 100 diff --git a/pitivi/action_search_bar.py b/pitivi/action_search_bar.py index 45b89c4e3..67d296280 100644 --- a/pitivi/action_search_bar.py +++ b/pitivi/action_search_bar.py @@ -48,7 +48,9 @@ class ActionSearchBar(Gtk.Window): self.entry.props.placeholder_text = _("Search Action") self.entry.set_hexpand(True) - self.entry.connect("key-press-event", self._entry_key_press_event_cb) + eventcontroller_key = Gtk.EventControllerKey() + eventcontroller_key.connect("key-pressed", self._entry_key_press_event_cb) + self.entry.add_controller(eventcontroller_key) self.entry.connect("changed", self._entry_changed_cb) self.treeview.connect("row-activated", self._treeview_row_activated_cb) @@ -153,23 +155,23 @@ class ActionSearchBar(Gtk.Window): row_path = self.model_filter.get_path(row_iter) self.treeview.scroll_to_cell(row_path, None, False, 0, 0) - def _entry_key_press_event_cb(self, entry, event): - if event.keyval == Gdk.KEY_Escape: + def _entry_key_press_event_cb(self, controller, keyval, keycode, state): + if keyval == Gdk.KEY_Escape: self.destroy() return True - if event.keyval == Gdk.KEY_Return: + if keyval == Gdk.KEY_Return: self.__activate_selected_action() return True - if event.keyval == Gdk.KEY_Up: + if keyval == Gdk.KEY_Up: selection = self.treeview.get_selection() model, row_iter = selection.get_selected() if row_iter: self.__select_row(model.iter_previous(row_iter)) return True - if event.keyval == Gdk.KEY_Down: + if keyval == Gdk.KEY_Down: selection = self.treeview.get_selection() model, row_iter = selection.get_selected() if row_iter: diff --git a/pitivi/clip_properties/alignment.py b/pitivi/clip_properties/alignment.py index 18f510098..f6f88c405 100644 --- a/pitivi/clip_properties/alignment.py +++ b/pitivi/clip_properties/alignment.py @@ -42,16 +42,20 @@ class AlignmentEditor(Gtk.Box, Loggable): Loggable.__init__(self) self._hovered_box = None - self.connect("button-release-event", self._button_release_event_cb) - self.connect("motion-notify-event", self._motion_notify_event_cb) - self.connect("leave-notify-event", self._leave_notify_event_cb) + eventcontroller_click = Gtk.GestureClick() + eventcontroller_motion = Gtk.EventControllerMotion() + eventcontroller_click.connect("released", self._button_release_event_cb) + eventcontroller_motion.connect("motion", self._motion_notify_event_cb) + eventcontroller_motion.connect("leave", self._leave_notify_event_cb) + self.add_controller(eventcontroller_click) + self.add_controller(eventcontroller_motion) self.add_events(Gdk.EventMask.POINTER_MOTION_MASK) - def _leave_notify_event_cb(self, unused_widget, _): + def _leave_notify_event_cb(self, controller): self._hovered_box = None self.queue_draw() - def _button_release_event_cb(self, widget, event): + def _button_release_event_cb(self, controller, n_pressed, x, y): if not self._hovered_box: return self.emit("align") @@ -85,8 +89,8 @@ class AlignmentEditor(Gtk.Box, Loggable): return int(coordinate) - def _motion_notify_event_cb(self, widget, event): - hovered_box = self._get_box(event.x, event.y) + def _motion_notify_event_cb(self, controller, x, y): + hovered_box = self._get_box(x, y) if hovered_box != self._hovered_box: self._hovered_box = hovered_box self.queue_draw() diff --git a/pitivi/dialogs/clipmediaprops.py b/pitivi/dialogs/clipmediaprops.py index e2f15cbc9..840fcdfbc 100644 --- a/pitivi/dialogs/clipmediaprops.py +++ b/pitivi/dialogs/clipmediaprops.py @@ -126,7 +126,9 @@ class ClipMediaPropsDialog: self.framerate_checkbutton.hide() self.video_header_label.set_markup("" + _("Image:") + "") - self.dialog.connect("key-press-event", self._key_press_cb) + eventcontroller_key = Gtk.EventControllerKey() + eventcontroller_key.connect("key-pressed", self._key_press_cb) + self.dialog.add_controller(eventcontroller_key) self.dialog.connect("response", self.__response_cb) self.dialog.show() @@ -154,7 +156,7 @@ class ClipMediaPropsDialog: self._apply() self.dialog.destroy() - def _key_press_cb(self, unused_widget, event): - if event.keyval in (Gdk.KEY_Escape, Gdk.KEY_Q, Gdk.KEY_q): + def _key_press_cb(self, controller, keyval, keycode, state): + if keyval in (Gdk.KEY_Escape, Gdk.KEY_Q, Gdk.KEY_q): self.dialog.destroy() return True diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 7a01da1f3..e35705b90 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -101,7 +101,9 @@ class EditorPerspective(Perspective, Loggable): """Sets up the UI.""" self.__setup_css() self._create_ui() - self.app.gui.connect("focus-in-event", self.__focus_in_event_cb) + eventcontroller_focus = Gtk.EventControllerFocus() + eventcontroller_focus.connect("enter", self.__focus_in_event_cb) + self.app.gui.add_controller(eventcontroller_focus) self.app.gui.connect("destroy", self._destroyed_cb) def activate_compact_mode(self): @@ -121,7 +123,7 @@ class EditorPerspective(Perspective, Loggable): style_context.add_provider_for_display(display, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) - def __focus_in_event_cb(self, unused_widget, unused_event): + def __focus_in_event_cb(self, unused_controller): ges_timeline = self.timeline_ui.timeline.ges_timeline if not ges_timeline: # Nothing to work with, Pitivi is starting up. @@ -840,7 +842,9 @@ class PreviewAssetWindow(Gtk.Window): self._previewer.preview_uri(self._asset.get_id()) self._previewer.show() - self.connect("key-press-event", self._key_press_event_cb) + eventcontroller_key = Gtk.EventControllerKey() + eventcontroller_key.connect("key-pressed", self._key_press_event_cb) + self.add_controller(eventcontroller_key) def preview(self): """Shows the window and starts the playback.""" @@ -883,7 +887,7 @@ class PreviewAssetWindow(Gtk.Window): new_height = max_width * img_height / img_width return int(max_width), int(new_height + controls_height) - def _key_press_event_cb(self, unused_widget, event): - if event.keyval == Gdk.KEY_Escape: + def _key_press_event_cb(self, controller, keyval, keycode, state): + if keyval == Gdk.KEY_Escape: self.destroy() return True diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index f15a432c3..3d4eb1cbb 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -147,8 +147,11 @@ class GreeterPerspective(Perspective): self.__recent_projects_listbox.set_selection_mode(Gtk.SelectionMode.NONE) self.__recent_projects_listbox.connect( "row-activated", self.__projects_row_activated_cb) - self.__recent_projects_listbox.connect( - "button-press-event", self.__projects_button_press_cb) + + listbox_eventcontroller = Gtk.GestureClick() + listbox_eventcontroller.connect("pressed", self.__projects_button_press_cb) + listbox_eventcontroller.set_button(3) + self.__recent_projects_listbox.add_controller(listbox_eventcontroller) self.__infobar = builder.get_object("infobar") self.__infobar.set_revealed(False) @@ -383,12 +386,12 @@ class GreeterPerspective(Perspective): else: self.app.project_manager.load_project(row.uri) - def __projects_button_press_cb(self, listbox, event): - if event.button == 3: - self.__start_selection_mode() - row = listbox.get_row_at_y(event.y) - if row: - row.select_button.set_active(True) + def __projects_button_press_cb(self, controller, n_pressed, x, y): + self.__start_selection_mode() + listbox = controller.get_widget() + row = listbox.get_row_at_y(y) + if row: + row.select_button.set_active(True) def __search_changed_cb(self, search_entry): search_hit = False diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index e76ddcfe7..8b2e03cd4 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -18,7 +18,6 @@ import html from gettext import gettext as _ -from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import GLib @@ -127,9 +126,13 @@ class PreviewWidget(Gtk.Grid, Loggable): self.seeker = Gtk.Scale.new(Gtk.Orientation.HORIZONTAL, self.pos_adj) self.seeker.set_hexpand(True) self.seeker.set_halign(Gtk.Align.FILL) - self.seeker.connect('button-press-event', self._on_seeker_press_cb) - self.seeker.connect('button-release-event', self._on_seeker_press_cb) - self.seeker.connect('motion-notify-event', self._on_motion_notify_cb) + seeker_eventcontroller_motion = Gtk.EventControllerMotion() + seeker_eventcontroller_click = Gtk.GestureClick() + seeker_eventcontroller_click.connect('pressed', self._on_seeker_press_cb) + seeker_eventcontroller_click.connect('released', self._on_seeker_release_cb) + seeker_eventcontroller_motion.connect('motion', self._on_motion_notify_cb) + self.seeker.add_controller(seeker_eventcontroller_click) + self.seeker.add_controller(seeker_eventcontroller_motion) self.seeker.show() self.bbox.prepend(self.seeker) @@ -344,25 +347,26 @@ class PreviewWidget(Gtk.Grid, Loggable): self.preview_image.hide() self.preview_video.hide() - def _on_seeker_press_cb(self, widget, event): + def _on_seeker_press_cb(self, controller, n_pressed, x, y): self.slider_being_used = True - if event.type == Gdk.EventType.BUTTON_PRESS: - self.countinuous_seek = True - if self.is_playing: - self.player.set_simple_state(Gst.State.PAUSED) - elif event.type == Gdk.EventType.BUTTON_RELEASE: - self.countinuous_seek = False - value = int(widget.get_value()) - self.player.simple_seek(value) - self.at_eos = False - if self.is_playing: - self.player.set_simple_state(Gst.State.PLAYING) - # Now, allow gobject timeout to continue updating the slider pos: - self.slider_being_used = False + self.countinuous_seek = True + if self.is_playing: + self.player.set_simple_state(Gst.State.PAUSED) + + def _on_seeker_release_cb(self, controller, n_pressed, x, y): + self.slider_being_used = True + self.countinuous_seek = False + value = int(self.seeker.get_value()) + self.player.simple_seek(value) + self.at_eos = False + if self.is_playing: + self.player.set_simple_state(Gst.State.PLAYING) + # Now, allow gobject timeout to continue updating the slider pos: + self.slider_being_used = False - def _on_motion_notify_cb(self, widget, event): + def _on_motion_notify_cb(self, controller, x, y): if self.countinuous_seek: - value = int(widget.get_value()) + value = int(self.seeker.get_value()) self.player.simple_seek(value) self.at_eos = False diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index caa753f2f..209a04336 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -587,8 +587,11 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.flowbox.set_hadjustment(self.scrollwin.get_hadjustment()) self.scrollwin.set_child(self.flowbox) - self.flowbox.connect("button-press-event", self._flowbox_button_press_event_cb) - self.flowbox.connect("button-release-event", self._flowbox_button_release_event_cb) + flowbox_eventcontroller = Gtk.GestureClick() + flowbox_eventcontroller.connect("pressed", self._flowbox_button_press_event_cb) + flowbox_eventcontroller.connect("released", self._flowbox_button_release_event_cb) + flowbox_eventcontroller.set_button(0) + self.flowbox.add_controller(flowbox_eventcontroller) self.flowbox.set_activate_on_single_click(False) self.flowbox.connect("child-activated", self._flowbox_child_activated_cb) self.flowbox.set_selection_mode(Gtk.SelectionMode.MULTIPLE) @@ -1532,13 +1535,14 @@ class MediaLibraryWidget(Gtk.Box, Loggable): path = child.get_index() self.emit("play", self.store[path].asset) - def _flowbox_button_press_event_cb(self, flowbox, event): - child = flowbox.get_child_at_pos(event.x, event.y) - if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS: + def _flowbox_button_press_event_cb(self, controller, n_pressed, x, y): + child = self.flowbox.get_child_at_pos(x, y) + if n_pressed == 2: # It is possible to double-click outside of clips pass else: - if not event.get_state() & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK): + # To be tested: https://amolenaar.github.io/pgi-docgen/Gtk-4.0/classes/EventController.html#Gtk.EventController.get_current_event_state + if not controller.get_current_event_state() & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK): # Ctrl or Shift key is not pressed. # It is a left or right mouse click. if child: @@ -1563,15 +1567,15 @@ class MediaLibraryWidget(Gtk.Box, Loggable): # to the Timeline. return self.rubberbanding - def _flowbox_button_release_event_cb(self, flowbox, event): + def _flowbox_button_release_event_cb(self, controller, n_pressed, x, y): if self.rubberbanding: self.rubberbanding = False - res, button = event.get_button() - if not res or button != 3: + button = controller.get_button() + if button != 3: return - child = self.flowbox.get_child_at_pos(event.x, event.y) + child = self.flowbox.get_child_at_pos(x, y) if child: if not child.is_selected(): self.flowbox.unselect_all() @@ -1587,8 +1591,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable): popover.props.position = Gtk.PositionType.BOTTOM rect = Gdk.Rectangle() - rect.x = event.x - rect.y = event.y + rect.x = x + rect.y = y rect.width = 1 rect.height = 1 popover.set_pointing_to(rect) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 4c4506087..ec3125491 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -161,9 +161,9 @@ class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): self._initial_value = 0 # The initial keyframe timestamp when a keyframe is being moved. self._initial_timestamp = 0 - # The initial event.x when a keyframe is being moved. + # The initial event x when a keyframe is being moved. self._initial_x = 0 - # The initial event.y when a keyframe is being moved. + # The initial event y when a keyframe is being moved. self._initial_y = 0 # The (offset, value) of both keyframes of the clicked keyframe line. self.__clicked_line = () @@ -172,10 +172,18 @@ class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): self.__hovered = False - self.connect("motion-notify-event", self.__motion_notify_event_cb) - self.connect("event", self._event_cb) + eventcontroller_click = Gtk.GestureClick() + eventcontroller_motion = Gtk.EventControllerMotion() + eventcontroller_legacy = Gtk.EventControllerLegacy() + eventcontroller_motion.connect("motion", self.__motion_notify_event_cb) + eventcontroller_legacy.connect("event", self._event_cb) self.connect("notify::height-request", self.__height_request_cb) - self.connect("button_release_event", self._button_release_event_cb) + eventcontroller_click.connect("released", self._button_release_event_cb) + eventcontroller_click.set_button(1) + + self.add_controller(eventcontroller_click) + self.add_controller(eventcontroller_motion) + self.add_controller(eventcontroller_legacy) self.mpl_connect('button_press_event', self._mpl_button_press_event_cb) self.mpl_connect('button_release_event', self._mpl_button_release_event_cb) @@ -275,14 +283,14 @@ class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): self._update_plots() self._timeline.ges_timeline.get_parent().commit_timeline() - def __motion_notify_event_cb(self, unused_widget, unused_event): + def __motion_notify_event_cb(self, unused_controller, x, y): # We need to do this here, because Matplotlib's callbacks can't stop # signal propagation. if self.handling_motion: return True return False - def _event_cb(self, unused_element, event): + def _event_cb(self, controller, event): if event.type == Gdk.EventType.LEAVE_NOTIFY: cursor = NORMAL_CURSOR self._timeline.set_cursor(cursor) @@ -415,10 +423,7 @@ class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): self._offset = None self.__clicked_line = () - def _button_release_event_cb(self, unused_widget, event): - if not event.get_button() == (True, 1): - return False - + def _button_release_event_cb(self, controller, n_pressed, x, y): dragged = self._dragged self._dragged = False @@ -1203,8 +1208,13 @@ class Clip(Gtk.Box, Loggable): set_state_flags_recurse(self, Gtk.StateFlags.SELECTED, are_set=self.ges_clip.selected) # Connect to Widget signals. - self.connect("button-release-event", self._button_release_event_cb) - self.connect("event", self._event_cb) + eventcontroller_click = Gtk.GestureClick() + eventcontroller_legacy = Gtk.EventControllerLegacy() + eventcontroller_click.connect("released", self._button_release_event_cb) + eventcontroller_legacy.connect("event", self._event_cb) + + self.add_controller(eventcontroller_click) + self.add_controller(eventcontroller_legacy) # Connect to GES signals. self.ges_clip.connect("notify::start", self._start_changed_cb) @@ -1302,7 +1312,7 @@ class Clip(Gtk.Box, Loggable): Gtk.Box.do_map(self) self.update_position() - def _button_release_event_cb(self, unused_widget, event): + def _button_release_event_cb(self, controller, n_pressed, x, y): self.debug("Button release event") if self.timeline.got_dragged: @@ -1311,8 +1321,8 @@ class Clip(Gtk.Box, Loggable): self.timeline.got_dragged = False return False - res, button = event.get_button() - if res and not button == 1: + button = controller.get_button() + if not button == 1: # Only the left mouse button selects. return False @@ -1322,7 +1332,7 @@ class Clip(Gtk.Box, Loggable): mode = SELECT_ADD else: mode = UNSELECT - clicked_layer, click_pos = self.timeline.get_clicked_layer_and_pos(event) + clicked_layer, click_pos = self.timeline.get_clicked_layer_and_pos(controller, x, y) self.timeline.set_selection_meta_info(clicked_layer, click_pos, mode) else: self.app.gui.editor.switch_context_tab(self.ges_clip) @@ -1355,7 +1365,7 @@ class Clip(Gtk.Box, Loggable): for handle in self.handles: handle.hide() - def _event_cb(self, element, event): + def _event_cb(self, controller, event): prelight = None if (event.type == Gdk.EventType.ENTER_NOTIFY and event.mode == Gdk.CrossingMode.NORMAL and diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 06a13f00c..4d9aab29d 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -107,7 +107,9 @@ class LayerControls(Gtk.Box, Loggable): self.name_entry.props.valign = Gtk.Align.CENTER self.name_entry.set_hexpand(True) self.name_entry.set_halign(Gtk.Align.FILL) - self.name_entry.connect("focus-out-event", self.__name_focus_out_cb) + eventcontroller_focus = Gtk.EventControllerFocus() + eventcontroller_focus.connect("leave", self.__name_focus_out_cb) + self.name_entry.add_controller(eventcontroller_focus) self.ges_layer.connect("notify-meta", self.__layer_rename_cb) self.__update_name() name_row.prepend(self.name_entry) @@ -155,7 +157,7 @@ class LayerControls(Gtk.Box, Loggable): return self.__update_name() - def __name_focus_out_cb(self, unused_widget, unused_event): + def __name_focus_out_cb(self, unused_controller): self.name_entry.delete_selection() current_name = self.ges_layer.ui.get_name() name = self.name_entry.get_text() diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index b74fe2b2e..619661fab 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -163,16 +163,18 @@ class Marquee(Gtk.Box, Loggable): self.props.width_request = -1 self.set_visible(False) - def set_start_position(self, event): + def set_start_position(self, controller, event_x, event_y): """Sets the first corner of the marquee. Args: - event (Gdk.EventButton): The button pressed event which might - start a select operation. + controller (Gtk.GestureClick): The controller responsible for handling + clicks. A pressed signal by it might start a select operation. + event_x: X cordinate of the event + event_y: Y cordinate of the event """ - event_widget = Gtk.get_event_widget(event) + event_widget = Gtk.get_widget(controller) self.start_x, self.start_y = event_widget.translate_coordinates( - self.layout.layers_vbox, event.x, event.y) + self.layout.layers_vbox, event_x, event_y) self.end_x, self.end_y = self.start_x, self.start_y self.get_parent().move(self, self.start_x, self.start_y) @@ -180,16 +182,18 @@ class Marquee(Gtk.Box, Loggable): self.props.height_request = 0 self.set_visible(True) - def move(self, event): + def move(self, controller, event_x, event_y): """Sets the second corner of the marquee. Args: - event (Gdk.EventMotion): The motion event which contains - the coordinates of the second corner. + controller (Gtk.EventControllerMotion): The controller responsible for handling + motion. + event_x: X cordinate of the event + event_y: Y cordinate of the event """ - event_widget = Gtk.get_event_widget(event) + event_widget = Gtk.get_widget(controller) self.end_x, self.end_y = event_widget.translate_coordinates( - self.layout.layers_vbox, event.x, event.y) + self.layout.layers_vbox, event_x, event_y) x = min(self.start_x, self.end_x) y = min(self.start_y, self.end_y) @@ -593,14 +597,24 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.ges_timeline.connect("snapping-started", self.__snapping_started_cb) self.ges_timeline.connect("snapping-ended", self.__snapping_ended_cb) - self.connect("button-press-event", self._button_press_event_cb) - self.connect("button-release-event", self._button_release_event_cb) - self.connect("motion-notify-event", self._motion_notify_event_cb) + eventcontroller_click = Gtk.GestureClick() + eventcontroller_motion = Gtk.EventControllerMotion() + eventcontroller_click.connect("pressed", self._button_press_event_cb) + eventcontroller_click.connect("released", self._button_release_event_cb) + eventcontroller_click.set_button(0) + eventcontroller_motion.connect("motion", self._motion_notify_event_cb) + self.add_controller(eventcontroller_click) + self.add_controller(eventcontroller_motion) mini = True - self.mini_layout_container.connect("button-press-event", self._button_press_event_cb, mini) - self.mini_layout_container.connect("button-release-event", self._button_release_event_cb, mini) - self.mini_layout_container.connect("motion-notify-event", self._motion_notify_event_cb, mini) + mini_eventcontroller_click = Gtk.GestureClick() + mini_eventcontroller_motion = Gtk.EventControllerMotion() + mini_eventcontroller_click.connect("pressed", self._button_press_event_cb, mini) + mini_eventcontroller_click.connect("released", self._button_release_event_cb, mini) + mini_eventcontroller_click.set_button(0) + mini_eventcontroller_motion.connect("motion", self._motion_notify_event_cb, mini) + self.mini_layout_container.add_controller(mini_eventcontroller_click) + self.mini_layout_container.add_controller(mini_eventcontroller_motion) self.layout.update_width() self.mini_layout.update_width() @@ -729,7 +743,8 @@ class Timeline(Gtk.Box, Zoomable, Loggable): # Gtk events management - def do_scroll_event(self, event): + def do_scroll_event(self, controller, dx, dy): + event = controller.get_current_event() res, delta_x, delta_y = event.get_scroll_deltas() if not res: res, direction = event.get_scroll_direction() @@ -745,7 +760,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.error("Could not handle %s scroll event", direction) return False - event_widget = Gtk.get_event_widget(event) + event_widget = Gtk.get_widget(controller) if event.get_state() & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK): # Zoom. @@ -825,22 +840,22 @@ class Timeline(Gtk.Box, Zoomable, Loggable): """ self.__next_seek_position = next_seek_position - def _button_press_event_cb(self, unused_widget, event, mini=False): + def _button_press_event_cb(self, controller, n_pressed, x, y, mini=False): """Handles a mouse button press event.""" - self.debug("PRESSED %s", event) + self.debug("PRESSED %s", controller) self.app.gui.editor.focus_timeline() - event_widget = Gtk.get_event_widget(event) + event_widget = Gtk.get_widget(controller) - res, button = event.get_button() - if res and button == 1: + button = controller.get_button() + if button == 1: self.dragging_element = self._get_parent_of_type(event_widget, Clip) if isinstance(event_widget, TrimHandle): self.__clicked_handle = event_widget self.debug("Dragging element is %s", self.dragging_element) if self.dragging_element: - self.__drag_start_x = event.x + self.__drag_start_x = x self._on_layer = self.dragging_element.ges_clip.props.layer else: layer_controls = self._get_parent_of_type(event_widget, LayerControls) @@ -851,34 +866,34 @@ class Timeline(Gtk.Box, Zoomable, Loggable): toplevel=True) else: if not mini: - self.layout.marquee.set_start_position(event) + self.layout.marquee.set_start_position(controller, x, y) else: - self.mini_layout.marquee.set_start_position(event) + self.mini_layout.marquee.set_start_position(controller, x, y) - self.scrubbing = res and button == 3 + self.scrubbing = button == 3 if self.scrubbing: - self._seek(event, mini) + self._seek(controller, x, y, mini) clip = self._get_parent_of_type(event_widget, Clip) if clip: clip.shrink_trim_handles() - self._scrolling = res and button == 2 + self._scrolling = button == 2 if self._scrolling: # pylint: disable=attribute-defined-outside-init - self._scroll_start_x = event.x - self._scroll_start_y = event.y + self._scroll_start_x = x + self._scroll_start_y = y - def _button_release_event_cb(self, unused_widget, event, mini=False): - self.debug("RELEASED %s", event) + def _button_release_event_cb(self, controller, n_pressed, x, y, mini=False): + self.debug("RELEASED %s", controller) allow_seek = not self.__got_dragged - res, button = event.get_button() + button = controller.get_button() if self.dragging_element: self.drag_end() elif self.__moving_layer: self.__end_moving_layer() return False - elif self.layout.marquee.is_visible() and res and button == 1: + elif self.layout.marquee.is_visible() and button == 1: if not mini: clips = self.layout.marquee.find_clips(mini=mini) self.selection.set_selection(clips, SELECT) @@ -892,30 +907,30 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self._scrolling = False - if allow_seek and res and button == 1: + if allow_seek and button == 1: if self.app.settings.leftClickAlsoSeeks: if self.__next_seek_position is not None: self._project.pipeline.simple_seek(self.__next_seek_position) self.__next_seek_position = None else: - event_widget = Gtk.get_event_widget(event) + event_widget = Gtk.get_widget(controller) if event_widget and self._get_parent_of_type(event_widget, LayerControls) is None: - self._seek(event, mini) + self._seek(controller, x, y, mini) # Allowing group clips selection by shift+clicking anywhere on the timeline. if self.get_parent().shift_mask: last_clicked_layer = self.last_clicked_layer if not last_clicked_layer: - clicked_layer, click_pos = self.get_clicked_layer_and_pos(event, mini=mini) + clicked_layer, click_pos = self.get_clicked_layer_and_pos(controller, x, y, mini=mini) self.set_selection_meta_info(clicked_layer, click_pos, SELECT) else: last_click_pos = self.last_click_pos - cur_clicked_layer, cur_click_pos = self.get_clicked_layer_and_pos(event, mini=mini) + cur_clicked_layer, cur_click_pos = self.get_clicked_layer_and_pos(controller, x, y, mini=mini) clips = self.get_clips_in_between( last_clicked_layer, cur_clicked_layer, last_click_pos, cur_click_pos) self.selection.set_selection(clips, SELECT) elif not self.get_parent().control_mask: - clicked_layer, click_pos = self.get_clicked_layer_and_pos(event, mini=mini) + clicked_layer, click_pos = self.get_clicked_layer_and_pos(controller, x, y, mini=mini) self.set_selection_meta_info(clicked_layer, click_pos, SELECT) self.__end_snap() @@ -931,11 +946,11 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.last_clicked_layer = clicked_layer self.last_click_pos = click_pos - def get_clicked_layer_and_pos(self, event, mini=False): + def get_clicked_layer_and_pos(self, controller, event_x, event_y, mini=False): """Gets layer and position in the timeline where user clicked.""" - event_widget = Gtk.get_event_widget(event) + event_widget = Gtk.get_widget(controller) layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox - x, y = event_widget.translate_coordinates(layers_box, event.x, event.y) + x, y = event_widget.translate_coordinates(layers_box, event_x, event_y) clicked_layer = self.get_layer_at(y, mini=mini)[0] ratio = self.calc_best_zoom_ratio() if mini else None click_pos = max(0, self.pixel_to_ns(x, zoomratio=ratio)) @@ -976,7 +991,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): for clip in layer.get_clips(): yield clip - def _motion_notify_event_cb(self, unused_widget, event, mini=False): + def _motion_notify_event_cb(self, controller, x, y, mini=False): if self.dragging_element: if self.dragging_group is None: self.dragging_group = self.selection.group() @@ -985,22 +1000,22 @@ class Timeline(Gtk.Box, Zoomable, Loggable): # Don't allow dragging a transition. return False - state = event.get_state() + state = controller.get_current_event_state() if isinstance(state, tuple): state = state[1] if not state & Gdk.ModifierType.BUTTON1_MASK: self.drag_end() return False - if self.got_dragged or self.__past_threshold(event): - event_widget = Gtk.get_event_widget(event) + if self.got_dragged or self.__past_threshold(controller, x): + event_widget = Gtk.get_widget(controller) layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox - x, y = event_widget.translate_coordinates(layers_box, event.x, event.y) + x, y = event_widget.translate_coordinates(layers_box, x, y) self.__drag_update(x, y, mini) self.got_dragged = True elif self.__moving_layer: - event_widget = Gtk.get_event_widget(event) - unused_x, y = event_widget.translate_coordinates(self, event.x, event.y) + event_widget = Gtk.get_widget(controller) + unused_x, y = event_widget.translate_coordinates(self, x, y) layer, unused_on_sep = self.get_layer_at( y, prefer_ges_layer=self.__moving_layer, past_middle_when_adjacent=True, mini=mini) @@ -1008,18 +1023,19 @@ class Timeline(Gtk.Box, Zoomable, Loggable): priority = layer.get_priority() self.move_layer(self.__moving_layer, priority) elif self.layout.marquee.is_visible(): - self.layout.marquee.move(event) + self.layout.marquee.move(controller, x, y) elif self.mini_layout.marquee.is_visible(): - self.mini_layout.marquee.move(event) + self.mini_layout.marquee.move(controller, x, y) elif self.scrubbing: - self._seek(event, mini) + self._seek(controller, x, y, mini) elif self._scrolling: - self.__scroll(event) + self.__scroll(x, y) return False - def __past_threshold(self, event): + def __past_threshold(self, controller, x): threshold = 0 + event = controller.get_current_event() tool = event.get_device_tool() if tool: if tool.get_tool_type() in {Gdk.DeviceToolType.PEN, @@ -1030,24 +1046,24 @@ class Timeline(Gtk.Box, Zoomable, Loggable): # the stylus while clicking. threshold = 3 - delta_x = abs(self.__drag_start_x - event.x) + delta_x = abs(self.__drag_start_x - x) return delta_x > threshold - def _seek(self, event, mini=False): - event_widget = Gtk.get_event_widget(event) + def _seek(self, controller, x, y, mini=False): + event_widget = Gtk.get_widget(controller) layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox - x, unused_y = event_widget.translate_coordinates(layers_box, event.x, event.y) + x2, unused_y = event_widget.translate_coordinates(layers_box, x, y) ratio = self.calc_best_zoom_ratio() if mini else None - position = max(0, self.pixel_to_ns(x, zoomratio=ratio)) + position = max(0, self.pixel_to_ns(x2, zoomratio=ratio)) self._project.pipeline.simple_seek(position) - def __scroll(self, event): + def __scroll(self, x, y): # determine how much to move the canvas - x_diff = self._scroll_start_x - event.x + x_diff = self._scroll_start_x - x self.hadj.set_value(self.hadj.get_value() + x_diff) - y_diff = self._scroll_start_y - event.y + y_diff = self._scroll_start_y - y self.vadj.set_value(self.vadj.get_value() + y_diff) def __hadj_value_changed_cb(self, hadj): @@ -2437,18 +2453,18 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): # Gtk widget virtual methods - def do_key_press_event(self, event): + def do_key_press_event(self, controller, keyval, keycode, state): # This is used both for changing the selection modes and for affecting # the seek keyboard shortcuts further below - if event.keyval == Gdk.KEY_Shift_L: + if keyval == Gdk.KEY_Shift_L: self.shift_mask = True - elif event.keyval == Gdk.KEY_Control_L: + elif keyval == Gdk.KEY_Control_L: self.control_mask = True - def do_key_release_event(self, event): - if event.keyval == Gdk.KEY_Shift_L: + def do_key_release_event(self, controller, keyval, keycode, state): + if keyval == Gdk.KEY_Shift_L: self.shift_mask = False - elif event.keyval == Gdk.KEY_Control_L: + elif keyval == Gdk.KEY_Control_L: self.control_mask = False def _seek_backward_one_second_cb(self, unused_action, unused_parameter): @@ -2520,11 +2536,11 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): if position is not None: clip.set_start(position) - def do_focus_in_event(self, unused_event): + def do_focus_in_event(self, unused_controller): self.log("Timeline has grabbed focus") self.update_actions() - def do_focus_out_event(self, unused_event): + def do_focus_out_event(self, unused_controller): self.log("Timeline has lost focus") self.update_actions() diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index 0b9d61f6d..a579b22f7 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -27,7 +27,6 @@ from typing import Tuple import cairo import numpy -from gi.repository import Gdk from gi.repository import GES from gi.repository import Gio from gi.repository import GObject @@ -354,41 +353,41 @@ class ToplevelWidget(Gtk.Box, Loggable): # Bounding box callbacks @Gtk.Template.Callback() - def _drawing_area_button_event_cb(self, widget, event): - res, button = event.get_button() - if not res or button != 1: + def _drawing_area_button_pressed_cb(self, controller, n_pressed, x, y): + if self.pipeline.get_simple_state() != Gst.State.PAUSED: return + self.x1 = x + self.y1 = y + self.drawing_area_width = self.drawing_area.get_allocated_width + self.drawing_area_height = self.drawing_area.get_allocated_height + + @Gtk.Template.Callback() + def _drawing_area_button_released_cb(self, controller, n_pressed, x, y): if self.pipeline.get_simple_state() != Gst.State.PAUSED: return - if event.get_event_type() == Gdk.EventType.BUTTON_PRESS: - self.x1 = event.x - self.y1 = event.y - self.drawing_area_width = self.drawing_area.get_allocated_width - self.drawing_area_height = self.drawing_area.get_allocated_height - elif event.get_event_type() == Gdk.EventType.BUTTON_RELEASE: - self.x2 = event.x - self.y2 = event.y - - # Convert the viewer coordinates to video coordinates. - factor: float = 1 / self.video_to_viewer_factor() - x = min(self.x1, self.x2) * factor - y = min(self.y1, self.y2) * factor - w = abs(self.x2 - self.x1) * factor - h = abs(self.y2 - self.y1) * factor - if w and h: - # Apply the selected area to the object. - if not self.current_object: - self._create_empty_object() - position = self.pipeline.get_position() - self.object_manager.update_object_position( - self.current_object, position, (x, y, w, h)) - - # Allow tracking. - self.track_button.props.sensitive = True - - self.__reset_selected_area() + self.x2 = x + self.y2 = y + + # Convert the viewer coordinates to video coordinates. + factor: float = 1 / self.video_to_viewer_factor() + x = min(self.x1, self.x2) * factor + y = min(self.y1, self.y2) * factor + w = abs(self.x2 - self.x1) * factor + h = abs(self.y2 - self.y1) * factor + if w and h: + # Apply the selected area to the object. + if not self.current_object: + self._create_empty_object() + position = self.pipeline.get_position() + self.object_manager.update_object_position( + self.current_object, position, (x, y, w, h)) + + # Allow tracking. + self.track_button.props.sensitive = True + + self.__reset_selected_area() def _create_empty_object(self): """Generates a new object and adds it to the object_manager.""" @@ -410,18 +409,18 @@ class ToplevelWidget(Gtk.Box, Loggable): self.drawing_area_width, self.drawing_area_height = None, None @Gtk.Template.Callback() - def _drawing_area_enter_notify_event_cb(self, widget, event): + def _drawing_area_enter_notify_event_cb(self, controller, x, y): self.app.gui.set_cursor("crosshair") @Gtk.Template.Callback() - def _drawing_area_leave_notify_event_cb(self, widget, event): + def _drawing_area_leave_notify_event_cb(self, controller): self.app.gui.set_cursor(NORMAL_CURSOR) @Gtk.Template.Callback() - def _drawing_area_motion_notify_event_cb(self, widget, event): + def _drawing_area_motion_notify_event_cb(self, controller, x, y): if self.x1 is not None: - self.x2 = event.x - self.y2 = event.y + self.x2 = x + self.y2 = y self.drawing_area.queue_draw() @Gtk.Template.Callback() diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index 150fc8a07..85bd48f74 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -887,8 +887,9 @@ def set_state_flags_recurse(widget, state_flags, are_set, ignored_classes=()): set_state_flags_recurse(child, state_flags, are_set, ignored_classes) -def disable_scroll_event_cb(widget, unused_event): - GObject.signal_stop_emission_by_name(widget, "scroll-event") +def disable_scroll_event_cb(controller, dx, dy): + widget = controller.get_widget() + GObject.signal_stop_emission_by_name(widget, "scroll") return False @@ -901,7 +902,9 @@ def disable_scroll(widget): widget.foreach(disable_scroll) if isinstance(widget, (Gtk.ComboBox, Gtk.Scale, Gtk.SpinButton)): - widget.connect("scroll-event", disable_scroll_event_cb) + eventcontroller_scroll = Gtk.EventControllerScroll() + eventcontroller_scroll.connect("scroll", disable_scroll_event_cb) + widget.add_controller(eventcontroller_scroll) def get_listbox_children(listbox): diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index a61004099..132a8606b 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -309,7 +309,9 @@ class TimeWidget(TextWidget, DynamicWidget): TextWidget.__init__(self, self.VALID_REGEX) TextWidget.set_width_chars(self, 10) self._framerate = None - self.text.connect("focus-out-event", self._focus_out_cb) + eventcontroller_focus = Gtk.EventControllerFocus() + eventcontroller_focus.connect("leave", self._focus_out_cb) + self.text.add_controller(eventcontroller_focus) def get_widget_value(self): timecode = TextWidget.get_widget_value(self) @@ -340,7 +342,7 @@ class TimeWidget(TextWidget, DynamicWidget): timecode = timecode[2:] TextWidget.set_widget_value(self, timecode, send_signal=send_signal) - def _focus_out_cb(self, widget, event): + def _focus_out_cb(self, controller): """Reset the text to display the current position of the playhead.""" if self.default is not None: self.set_widget_value(self.default) @@ -349,8 +351,10 @@ class TimeWidget(TextWidget, DynamicWidget): return self.connect("activate", activate_cb) def connect_focus_events(self, focus_in_cb, focus_out_cb): - focus_in_handler_id = self.text.connect("focus-in-event", focus_in_cb) - focus_out_handler_id = self.text.connect("focus-out-event", focus_out_cb) + eventcontroller_focus = Gtk.EventControllerFocus() + focus_in_handler_id = eventcontroller_focus.connect("enter", focus_in_cb) + focus_out_handler_id = eventcontroller_focus.connect("leave", focus_out_cb) + self.text.add_controller(eventcontroller_focus) return [focus_in_handler_id, focus_out_handler_id] def set_framerate(self, framerate): @@ -1249,7 +1253,9 @@ class ZoomBox(Gtk.Grid, Zoomable): # Setting _zoom_adjustment's value must be done after we create the # zoom slider, otherwise the slider remains at the leftmost position. self._zoom_adjustment.set_value(Zoomable.get_current_zoom_level()) - zoomslider.connect("scroll-event", self._zoom_slider_scroll_cb) + eventcontroller_scroll = Gtk.EventControllerScroll() + eventcontroller_scroll.connect("scroll", self._zoom_slider_scroll_cb) + zoomslider.add_controller(eventcontroller_scroll) zoomslider.connect("value-changed", self._zoom_slider_changed_cb) zoomslider.connect("query-tooltip", self._zoom_slider_query_tooltip_cb) zoomslider.set_has_tooltip(True) @@ -1276,18 +1282,18 @@ class ZoomBox(Gtk.Grid, Zoomable): def _zoom_fit_cb(self, button): self.timeline.timeline.set_best_zoom_ratio(allow_zoom_in=True) - def _zoom_slider_scroll_cb(self, unused, event): + def _zoom_slider_scroll_cb(self, controller, dx, dy): delta = 0 + event = controller.get_current_event() if event.direction in [Gdk.ScrollDirection.UP, Gdk.ScrollDirection.RIGHT]: delta = 1 elif event.direction in [Gdk.ScrollDirection.DOWN, Gdk.ScrollDirection.LEFT]: delta = -1 elif event.direction in [Gdk.ScrollDirection.SMOOTH]: - unused_res, delta_x, delta_y = event.get_scroll_deltas() - if delta_x: - delta = math.copysign(1, delta_x) - elif delta_y: - delta = math.copysign(1, -delta_y) + if dx: + delta = math.copysign(1, dx) + elif dy: + delta = math.copysign(1, -dy) if delta: Zoomable.set_zoom_level(Zoomable.get_current_zoom_level() + delta) @@ -1418,7 +1424,10 @@ class ColorPickerButton(Gtk.Button): return # Start tracking the mouse events self.dropper_grab_widget.grab_add() - self.dropper_grab_widget.connect("button-release-event", self.button_release_event_cb) + dropper_eventcontroller_click = Gtk.GestureClick() + dropper_eventcontroller_click.connect("released", self.button_release_event_cb) + dropper_eventcontroller_click.set_button(1) + self.dropper_grab_widget.add_controller(dropper_eventcontroller_click) def make_cursor_picker(self, screen): # Get color-picker cursor if it exists in the current theme else fallback to generating it ourself @@ -1431,11 +1440,9 @@ class ColorPickerButton(Gtk.Button): cursor = Gdk.Cursor.new_from_texture(texture, DROPPER_X_HOT, DROPPER_Y_HOT) return cursor - def button_release_event_cb(self, widget, event): - if event.button != Gdk.BUTTON_PRIMARY: - return - - self.grab_color_at_pointer(event.get_screen(), event.x_root, event.y_root) + def button_release_event_cb(self, controller, n_pressed, x, y): + event = controller.get_current_event() + self.grab_color_at_pointer(event.get_display(), x, y) self.emit("value-changed") self.shutdown_eyedropper() diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 1407299dc..32a5f81b5 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -264,11 +264,17 @@ class ViewerContainer(Gtk.Box, Loggable): Gdk.EventMask.POINTER_MOTION_MASK) hpane = self.app.gui.editor.mainhpaned vpane = self.app.gui.editor.toplevel_widget + + eventcontroller_click = Gtk.GestureClick() + eventcontroller_motion = Gtk.EventControllerMotion() + corner.connect("draw", self.__corner_draw_cb, lines, space, margin) - corner.connect("enter-notify-event", self.__corner_enter_notify_cb) - corner.connect("button-press-event", self.__corner_button_press_cb, hpane, vpane) - corner.connect("button-release-event", self.__corner_button_release_cb) - corner.connect("motion-notify-event", self.__corner_motion_notify_cb, hpane, vpane) + eventcontroller_motion.connect("enter", self.__corner_enter_notify_cb) + eventcontroller_click.connect("pressed", self.__corner_button_press_cb, hpane, vpane) + eventcontroller_click.connect("released", self.__corner_button_release_cb) + eventcontroller_motion.connect("motion", self.__corner_motion_notify_cb, hpane, vpane) + corner.add_controller(eventcontroller_click) + corner.add_controller(eventcontroller_motion) self.append(corner) # Peak Meters @@ -350,7 +356,9 @@ class ViewerContainer(Gtk.Box, Loggable): self.timecode_entry.props.margin_start = 15 self.timecode_entry.props.margin_end = 15 self.timecode_entry.connect_activate_event(self._entry_activate_cb) - self.timecode_entry.connect("key_press_event", self._entry_key_press_event_cb) + timecode_eventcontroller_key = Gtk.EventControllerKey() + timecode_eventcontroller_key.connect("key_pressed", self._entry_key_press_event_cb) + self.timecode_entry.add_controller(timecode_eventcontroller_key) bbox.prepend(self.timecode_entry) self.undock_button = Gtk.Button.new_from_icon_name("view-restore-symbolic") @@ -435,24 +443,27 @@ class ViewerContainer(Gtk.Box, Loggable): self.__cursor = Gdk.Cursor.new_from_name("sw-resize") widget.set_cursor(self.__cursor) - def __corner_button_press_cb(self, unused_widget, event, hpane, vpane): - if event.button == 1: + def __corner_button_press_cb(self, controller, n_pressed, x, y, data, hpane, vpane): + if controller.get_button() == 1: # The mouse pointer position is w.r.t the root of the screen # whereas the positions of panes is w.r.t the root of the # mainwindow. We need to find the translation that takes us # from screen coordinate system to mainwindow coordinate system. - self.__translation = (event.x_root - hpane.get_position(), - event.y_root - vpane.get_position()) - def __corner_button_release_cb(self, unused_widget, unused_event): + # ToDo - Used to be event.x_root, no proper replacement found + self.__translation = (x - hpane.get_position(), + y - vpane.get_position()) + + def __corner_button_release_cb(self, unused_controller, n_pressed, x, y): self.__translation = None - def __corner_motion_notify_cb(self, unused_widget, event, hpane, vpane): + def __corner_motion_notify_cb(self, controller, x, y, data, hpane, vpane): if self.__translation is None: return - hpane.set_position(event.x_root - self.__translation[0]) - vpane.set_position(event.y_root - self.__translation[1]) + # ToDo - Used to be event.x_root, no proper replacement found + hpane.set_position(x - self.__translation[0]) + vpane.set_position(y - self.__translation[1]) def __peak_meter_scale_configure_event_cb(self, unused_widget, unused_event): container_height = self.viewer_row_box.get_allocated_height() @@ -473,9 +484,9 @@ class ViewerContainer(Gtk.Box, Loggable): self.app.gui.editor.timeline_ui.timeline.scroll_to_playhead( align=Gtk.Align.CENTER, when_not_in_view=True) - def _entry_key_press_event_cb(self, widget, event): + def _entry_key_press_event_cb(self, controller, keyval, keycode, state): """Handles the key press events in the timecode_entry widget.""" - if event.keyval == Gdk.KEY_Escape: + if keyval == Gdk.KEY_Escape: self.app.gui.editor.focus_timeline() # Active Timeline calllbacks diff --git a/plugins/console/widgets.py b/plugins/console/widgets.py index 80fc0ea5c..3f900f985 100644 --- a/plugins/console/widgets.py +++ b/plugins/console/widgets.py @@ -64,7 +64,9 @@ class ConsoleWidget(Gtk.ScrolledWindow): self._view.set_editable(True) self.set_child(self._view) - self._view.connect("key-press-event", self.__key_press_event_cb) + eventcontroller_key = Gtk.EventControllerKey() + eventcontroller_key.connect("key-pressed", self.__key_press_event_cb) + self._view.add_controller(eventcontroller_key) buf.connect("mark-set", self.__mark_set_cb) buf.connect("insert-text", self.__insert_text_cb) @@ -136,30 +138,30 @@ class ConsoleWidget(Gtk.ScrolledWindow): self._view.get_buffer().error.set_property("foreground-rgba", color) # pylint: disable=too-many-return-statements - def __key_press_event_cb(self, view, event): - buf = view.get_buffer() - state = event.state & Gtk.accelerator_get_default_mod_mask() + def __key_press_event_cb(self, controller, keyval, keycode, state): + buf = controller.get_widget().get_buffer() + state = state & Gtk.accelerator_get_default_mod_mask() ctrl = state & Gdk.ModifierType.CONTROL_MASK - if event.keyval == Gdk.KEY_Return: + if keyval == Gdk.KEY_Return: buf.process_command_line() return True - if event.keyval in (Gdk.KEY_KP_Down, Gdk.KEY_Down): + if keyval in (Gdk.KEY_KP_Down, Gdk.KEY_Down): buf.history.down(buf.get_command_line()) return True - if event.keyval in (Gdk.KEY_KP_Up, Gdk.KEY_Up): + if keyval in (Gdk.KEY_KP_Up, Gdk.KEY_Up): buf.history.up(buf.get_command_line()) return True - if event.keyval in (Gdk.KEY_KP_Left, Gdk.KEY_Left, Gdk.KEY_BackSpace): + if keyval in (Gdk.KEY_KP_Left, Gdk.KEY_Left, Gdk.KEY_BackSpace): return buf.is_cursor(at=True) - if event.keyval in (Gdk.KEY_KP_Home, Gdk.KEY_Home): + if keyval in (Gdk.KEY_KP_Home, Gdk.KEY_Home): buf.place_cursor(buf.get_iter_at_mark(buf.prompt_mark)) return True - if (ctrl and event.keyval == Gdk.KEY_d) or event.keyval == Gdk.KEY_Escape: + if (ctrl and keyval == Gdk.KEY_d) or keyval == Gdk.KEY_Escape: return self.emit("eof") return False -- GitLab From 34be9f89706c80709cd888f0e49f3bed9441cc01 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 1 Sep 2022 23:28:44 +0530 Subject: [PATCH 064/132] Drop use of label_xalign --- data/ui/clipmediaprops.ui | 2 -- data/ui/customwidgets/alpha.ui | 1 - .../ui/customwidgets/frei0r-filter-3-point-color-balance.ui | 6 ------ data/ui/renderingdialog.ui | 2 -- data/ui/titleeditor.ui | 3 --- data/ui/trackerperspective.ui | 1 - 6 files changed, 15 deletions(-) diff --git a/data/ui/clipmediaprops.ui b/data/ui/clipmediaprops.ui index 2187af6b8..563cc1637 100644 --- a/data/ui/clipmediaprops.ui +++ b/data/ui/clipmediaprops.ui @@ -26,7 +26,6 @@ True False - 0 True fill @@ -146,7 +145,6 @@ True False - 0 True fill diff --git a/data/ui/customwidgets/alpha.ui b/data/ui/customwidgets/alpha.ui index 9993a9607..2b8d777ff 100644 --- a/data/ui/customwidgets/alpha.ui +++ b/data/ui/customwidgets/alpha.ui @@ -434,7 +434,6 @@ True False - 0 diff --git a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui index 035471c74..e2c27d31d 100644 --- a/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui +++ b/data/ui/customwidgets/frei0r-filter-3-point-color-balance.ui @@ -251,7 +251,6 @@ True False - 0 @@ -265,7 +264,6 @@ True False - 0 True @@ -299,7 +297,6 @@ True False - 0 @@ -313,7 +310,6 @@ True False - 0 True @@ -347,7 +343,6 @@ True False - 0 @@ -361,7 +356,6 @@ True False - 0 True diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index be7963c33..dc276071a 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -305,7 +305,6 @@ This option is a good trade-off between quality of the rendered video and stabil True False - 0 True @@ -424,7 +423,6 @@ This option is a good trade-off between quality of the rendered video and stabil True False - 0 True diff --git a/data/ui/titleeditor.ui b/data/ui/titleeditor.ui index a13a5b420..c2c1aae1e 100644 --- a/data/ui/titleeditor.ui +++ b/data/ui/titleeditor.ui @@ -87,7 +87,6 @@ picker1 True False - 0 fill @@ -112,7 +111,6 @@ picker2 True False - 0 fill @@ -137,7 +135,6 @@ picker3 True False - 0 fill diff --git a/data/ui/trackerperspective.ui b/data/ui/trackerperspective.ui index e86d174b4..075fc8c9c 100644 --- a/data/ui/trackerperspective.ui +++ b/data/ui/trackerperspective.ui @@ -170,7 +170,6 @@ True False - 0 False fill -- GitLab From e3a3e96d2190fdd23f204e8b21c95dbbcff21817 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 1 Sep 2022 23:35:04 +0530 Subject: [PATCH 065/132] Update clipcompositing.ui to Gtk4 --- data/ui/clipcompositing.ui | 78 +++++++++++++------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/data/ui/clipcompositing.ui b/data/ui/clipcompositing.ui index dbf91eaea..01441f76a 100644 --- a/data/ui/clipcompositing.ui +++ b/data/ui/clipcompositing.ui @@ -1,7 +1,6 @@ - - + 1 1 @@ -14,10 +13,7 @@ 5 - - True - False start start 10 @@ -28,11 +24,9 @@ 6 - True - False end - True - Fade-in: + 1 + Fade-in: 0 0 @@ -42,9 +36,7 @@ - True - False - seconds + seconds 2 0 @@ -53,8 +45,7 @@ - True - True + 1 fade_in_adjustment 0.10 2 @@ -66,11 +57,11 @@ + 1 150 - True - True + 1 1 - True + 1 fade_in_adjustment 1 left @@ -82,11 +73,9 @@ - True - False end - True - Fade-out: + 1 + Fade-out: 0 0 @@ -96,8 +85,7 @@ - True - True + 1 fade_out_adjustment 0.10 2 @@ -109,9 +97,7 @@ - True - False - seconds + seconds 2 1 @@ -120,10 +106,10 @@ + 1 150 - True - True - True + 1 + 1 fade_out_adjustment 1 @@ -134,13 +120,12 @@ - True - True - False - True - Reset fade-in + 1 + 0 + 1 + Reset fade-in edit-clear-all-symbolic - False + 0 4 @@ -150,13 +135,12 @@ - True - True - False - True - Reset fade-out + 1 + 0 + 1 + Reset fade-out edit-clear-all-symbolic - False + 0 4 @@ -166,10 +150,8 @@ - True - False end - Blending: + Blending: 0 2 @@ -178,19 +160,11 @@ - True - False start - - 1 - 2 - 3 - - -- GitLab From d95d5d6836777846b10d84884016a1f4223cd20b Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 2 Sep 2022 23:35:23 +0530 Subject: [PATCH 066/132] Replace deprecated margin property --- pitivi/clipproperties.py | 5 ++++- pitivi/dialogs/prefs.py | 23 ++++++++++++++++++----- pitivi/effects.py | 24 +++++++++++++++++++++--- pitivi/greeterperspective.py | 8 +++++++- pitivi/medialibrary.py | 20 ++++++++++++++++---- pitivi/render.py | 5 ++++- pitivi/timeline/timeline.py | 5 ++++- pitivi/trackerperspective.py | 11 +++++++++-- pitivi/transitions.py | 5 ++++- pitivi/viewer/guidelines.py | 5 ++++- 10 files changed, 91 insertions(+), 20 deletions(-) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index b2aeb2785..eaa908307 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -157,7 +157,10 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): def create_helper_box(self): """Creates the widgets to display when no clip is selected.""" box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - box.props.margin = PADDING + box.props.margin_top = PADDING + box.props.margin_bottom = PADDING + box.props.margin_start = PADDING + box.props.margin_end = PADDING label = Gtk.Label.new(_("Select a clip on the timeline to configure its properties and effects or create a new clip:")) label.set_wrap(True) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 8e5847c4f..06bdbf8fb 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -237,7 +237,10 @@ class PreferencesDialog(Loggable): listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) - listbox.props.margin = PADDING * 2 + listbox.props.margin_top = PADDING * 2 + listbox.props.margin_bottom = PADDING * 2 + listbox.props.margin_start = PADDING * 2 + listbox.props.margin_end = PADDING * 2 listbox.add_css_class('prefs_list') container.prepend(listbox) @@ -410,7 +413,10 @@ class PreferencesDialog(Loggable): self.content_box.set_header_func(self._add_header_func, None) self.content_box.connect("row-activated", self.__row_activated_cb) self.content_box.set_selection_mode(Gtk.SelectionMode.NONE) - self.content_box.props.margin = PADDING * 3 + self.content_box.props.margin_top = PADDING * 3 + self.content_box.props.margin_bottom = PADDING * 3 + self.content_box.props.margin_start = PADDING * 3 + self.content_box.props.margin_end = PADDING * 3 self.content_box.props.halign = Gtk.Align.CENTER self.content_box.add_css_class('prefs_list') @@ -664,7 +670,10 @@ class CustomShortcutDialog(Gtk.Dialog): self.conflict_label.props.wrap = True content_area = self.get_content_area() - content_area.props.margin = PADDING * 3 + content_area.props.margin_top = PADDING * 3 + content_area.props.margin_bottom = PADDING * 3 + content_area.props.margin_start = PADDING * 3 + content_area.props.margin_end = PADDING * 3 content_area.set_child(prompt_label) content_area.set_child(self.accelerator_label) content_area.set_child(self.conflict_label) @@ -793,7 +802,9 @@ class PluginsBox(Gtk.ListBox): self.set_header_func(self._add_header_func, None) self.bind_model(self.list_store, self._create_widget_func, None) - self.props.margin = PADDING * 3 + self.props.margin_bottom = PADDING * 3 + self.props.margin_start = PADDING * 3 + self.props.margin_end = PADDING * 3 self.props.margin_top = 0 self.add_css_class('prefs_list') @@ -915,7 +926,9 @@ class PluginPreferencesPage(Gtk.ScrolledWindow): # We could use Gtk.ListBox.set_placeholder, but it # appears bad inside the list widget. placeholder_label = Gtk.Label.new(_("No plugins available")) - placeholder_label.props.margin = 4 * PADDING + placeholder_label.props.margin_end = 4 * PADDING + placeholder_label.props.margin_start = 4 * PADDING + placeholder_label.props.margin_bottom = 4 * PADDING placeholder_label.props.margin_top = 10 * PADDING placeholder_label.show() plugins_box = placeholder_label diff --git a/pitivi/effects.py b/pitivi/effects.py index de5eb7b95..c6012b2ad 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -471,7 +471,13 @@ class EffectListWidget(Gtk.Box, Loggable): def _create_category_widget(self, category): """Creates an expander for the given category.""" - expander = Gtk.Expander(label=category, margin=SPACING) + expander = Gtk.Expander( + label=category, + margin_top=SPACING, + margin_bottom=SPACING, + margin_start=SPACING, + margin_end=SPACING + ) listbox = Gtk.ListBox(activate_on_single_click=False) listbox.connect("row-activated", self.effects_listbox_row_activated_cb) @@ -484,7 +490,13 @@ class EffectListWidget(Gtk.Box, Loggable): """Creates list box row for the given effect.""" effect_info = self.app.effects.get_info(effect_name) - effect_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, margin=SPACING / 2) + effect_box = Gtk.Box( + orientation=Gtk.Orientation.HORIZONTAL, + margin_top=SPACING / 2, + margin_bottom=SPACING / 2, + margin_start=SPACING / 2, + margin_end=SPACING / 2 + ) effect_box.effect_name = effect_name effect_box.set_tooltip_text(effect_info.description) label = Gtk.Label.new(effect_info.human_name) @@ -673,7 +685,13 @@ class EffectsPopover(Gtk.Popover, Loggable): self.app = app - vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, margin=PADDING) + vbox = Gtk.Box( + orientation=Gtk.Orientation.VERTICAL, + margin_top=PADDING, + margin_bottom=PADDING, + margin_start=PADDING, + margin_end=PADDING + ) self.search_entry = Gtk.SearchEntry() self.search_entry.connect("search-changed", self._search_entry_cb) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 3d4eb1cbb..6a512fede 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -444,7 +444,13 @@ class GreeterPerspective(Perspective): def __create_warnings_popover(self): """Creates a popover listing missing soft dependencies.""" popover = Gtk.Popover() - box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, margin=PADDING * 3) + box = Gtk.Box( + orientation=Gtk.Orientation.VERTICAL, + margin_top=PADDING * 3, + margin_bottom=PADDING * 3, + margin_start=PADDING * 3, + margin_end=PADDING * 3 + ) label = Gtk.Label.new(_("To enable additional features, please install the following packages and restart Pitivi:")) label.props.halign = Gtk.Align.START diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 209a04336..bfc50eb5f 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -656,7 +656,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable): def create_iconview_widget_func(self, item): box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) box.set_halign(Gtk.Align.CENTER) - box.props.margin = PADDING / 2 + box.props.margin_top = PADDING / 2 + box.props.margin_bottom = PADDING / 2 + box.props.margin_start = PADDING / 2 + box.props.margin_end = PADDING / 2 icon = Gtk.Image.new_from_pixbuf(item.icon_128) @@ -667,7 +670,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable): def create_listview_widget_func(self, item): box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - box.props.margin = PADDING + box.props.margin_top = PADDING + box.props.margin_bottom = PADDING + box.props.margin_start = PADDING + box.props.margin_end = PADDING box.set_spacing(SPACING) icon = Gtk.Image.new_from_pixbuf(item.icon_64) @@ -1242,7 +1248,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable): new_entry_box.prepend(add_tag_button) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - box.props.margin = PADDING + box.props.margin_top = PADDING + box.props.margin_bottom = PADDING + box.props.margin_start = PADDING + box.props.margin_end = PADDING popover_heading.props.margin_top = SPACING popover_heading.props.margin_bottom = SPACING popover_heading.props.margin_start = SPACING @@ -1261,7 +1270,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable): def create_tagslist_widget_func(self, tag_item: TagStoreItem): """Converts a tag item to a widget.""" box = Gtk.ListBoxRow() - box.props.margin = PADDING + box.props.margin_top = PADDING + box.props.margin_bottom = PADDING + box.props.margin_start = PADDING + box.props.margin_end = PADDING checkbutton = Gtk.CheckButton.new_with_label(tag_item.name) diff --git a/pitivi/render.py b/pitivi/render.py index 45ba83bb6..14e007aaf 100644 --- a/pitivi/render.py +++ b/pitivi/render.py @@ -159,7 +159,10 @@ class PresetBoxRow(Gtk.ListBoxRow): grid.set_row_spacing(6) grid.set_column_spacing(10) grid.set_row_homogeneous(False) - grid.props.margin = 6 + grid.props.margin_top = 6 + grid.props.margin_bottom = 6 + grid.props.margin_start = 6 + grid.props.margin_end = 6 self.set_child(grid) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 619661fab..9cb7c66e4 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -424,7 +424,10 @@ class Timeline(Gtk.Box, Zoomable, Loggable): hbox.prepend(scrolled_window) self.add_layer_button = Gtk.Button.new_with_label(_("Add layer")) - self.add_layer_button.props.margin = SPACING + self.add_layer_button.props.margin_top = SPACING + self.add_layer_button.props.margin_bottom = SPACING + self.add_layer_button.props.margin_start = SPACING + self.add_layer_button.props.margin_end = SPACING self.add_layer_button.set_halign(Gtk.Align.CENTER) self.add_layer_button.show() self.add_layer_button.set_action_name("timeline.add-layer") diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index a579b22f7..d220fd93b 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -183,7 +183,8 @@ class TrackedObjectRow(Gtk.ListBoxRow): self.name: str = name label = Gtk.Label.new(name) - label.props.margin = SPACING + label.props.margin_top = SPACING + label.props.margin_bottom = SPACING label.props.margin_end = PADDING label.props.margin_start = PADDING label.props.halign = Gtk.Align.START @@ -702,7 +703,13 @@ class CoverObjectPopover(Gtk.Popover, Loggable): self.scroll_window.set_hexpand(True) self.scroll_window.set_halign(Gtk.Align.FILL) - vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, margin=PADDING) + vbox = Gtk.Box( + orientation=Gtk.Orientation.VERTICAL, + margin_top=PADDING, + margin_bottom=PADDING, + margin_start=PADDING, + margin_end=PADDING + ) vbox.prepend(self.scroll_window) self.set_child(vbox) diff --git a/pitivi/transitions.py b/pitivi/transitions.py index 72ce08c21..66cc742dd 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -74,7 +74,10 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.searchbar.append(self.search_entry) self.props_widgets = Gtk.Grid() - self.props_widgets.props.margin = PADDING + self.props_widgets.props.margin_top = PADDING + self.props_widgets.props.margin_bottom = PADDING + self.props_widgets.props.margin_start = PADDING + self.props_widgets.props.margin_end = PADDING self.props_widgets.props.column_spacing = SPACING self.border_mode_normal = Gtk.CheckButton( diff --git a/pitivi/viewer/guidelines.py b/pitivi/viewer/guidelines.py index b506485ac..b32e957a8 100644 --- a/pitivi/viewer/guidelines.py +++ b/pitivi/viewer/guidelines.py @@ -87,7 +87,10 @@ class GuidelinesPopover(Gtk.Popover): grid = Gtk.Grid() grid.props.row_spacing = SPACING grid.props.column_spacing = SPACING - grid.props.margin = SPACING * 2 + grid.props.margin_top = SPACING * 2 + grid.props.margin_bottom = SPACING * 2 + grid.props.margin_start = SPACING * 2 + grid.props.margin_end = SPACING * 2 label = Gtk.Label.new(_("Composition Guidelines")) label.props.wrap = True -- GitLab From f48b29a380eec030900e947467a8f2d090a75c2a Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 3 Sep 2022 00:09:41 +0530 Subject: [PATCH 067/132] Adapt to GtkMenuButton signal change --- pitivi/clipproperties.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index eaa908307..8e607d9ce 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -659,18 +659,16 @@ class EffectProperties(Gtk.Expander, Loggable): self.connect("drag-leave", self._drag_leave_cb) self.connect("drag-data-received", self._drag_data_received_cb) - self.add_effect_button.connect("toggled", self._add_effect_button_toggled_cb) + self.add_effect_button.connect("activate", self._add_effect_button_toggled_cb) if self.cover_object_button: - self.cover_object_button.connect("toggled", self._cover_object_button_toggled_cb) + self.cover_object_button.connect("activate", self._cover_object_button_toggled_cb) def _add_effect_button_toggled_cb(self, button): # MenuButton interacts directly with the popover, bypassing our subclassed method - if button.props.active: - self.effect_popover.search_entry.set_text("") + self.effect_popover.search_entry.set_text("") def _cover_object_button_toggled_cb(self, button): - if button.props.active: - self.cover_popover.update_object_list() + self.cover_popover.update_object_list() def _create_effect_row(self, effect): if is_time_effect(effect): -- GitLab From bad72087ec09529fc53f13cbafd04f226a920330 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 3 Sep 2022 15:14:40 +0530 Subject: [PATCH 068/132] Remove deprecated GtkBin get_child --- pitivi/effects.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pitivi/effects.py b/pitivi/effects.py index c6012b2ad..ae4d493d7 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -568,7 +568,7 @@ class EffectListWidget(Gtk.Box, Loggable): def effects_listbox_row_activated_cb(self, listbox, row): """Handles the activation of a row representing an effect.""" - effect_box = row.get_child().get_child() + effect_box = row.get_first_child().get_first_child() self.apply_effect(effect_box.effect_name) def apply_effect(self, effect_name): @@ -615,7 +615,7 @@ class EffectListWidget(Gtk.Box, Loggable): # Find and sync state in other listboxes for listbox in all_effect_listboxes: for row in get_listbox_children(listbox): - effect_box = row.get_child().get_child() + effect_box = row.get_first_child().get_first_child() if effect == effect_box.effect_name: fav_button = effect_box.get_last_child() # Sync the state with the clicked button @@ -631,7 +631,7 @@ class EffectListWidget(Gtk.Box, Loggable): def _favourites_filter(self, row): """Filters search_view to show favourites.""" - effect_box = row.get_child().get_child() + effect_box = row.get_first_child().get_first_child() effect_name = effect_box.effect_name return effect_name in self.app.settings.favourite_effects @@ -648,7 +648,7 @@ class EffectListWidget(Gtk.Box, Loggable): def _search_filter(self, row): """Filters search_view to show search results.""" - effect_box = row.get_child().get_child() + effect_box = row.get_first_child().get_first_child() label = get_widget_children(effect_box)[1] label_text = label.get_text().lower() @@ -719,7 +719,7 @@ class EffectsPopover(Gtk.Popover, Loggable): self.set_child(vbox) def _effect_row_activate_cb(self, listbox, row): - effect_box = row.get_child().get_child() + effect_box = row.get_first_child().get_first_child() self.app.gui.editor.effectlist.apply_effect(effect_box.effect_name) self.hide() @@ -727,7 +727,7 @@ class EffectsPopover(Gtk.Popover, Loggable): self.listbox.invalidate_filter() def _search_filter(self, row): - effect_box = row.get_child().get_child() + effect_box = row.get_first_child().get_first_child() label = effect_box.get_first_child() label_text = label.get_text().lower() -- GitLab From 7dc08fd98be87e4bd17e1558ddd41ffac9a25a3d Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 3 Sep 2022 18:17:16 +0530 Subject: [PATCH 069/132] Remove Window deprecated remove property --- pitivi/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 849cad946..dd8ecf6fc 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -281,7 +281,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): # Remove the current perspective before adding the # specified perspective because we can only add one # toplevel widget to the main window at a time. - self.remove(self.__perspective.toplevel_widget) + self.set_child() self.log("Displaying perspective: %s", type(perspective).__name__) self.__perspective = perspective self.set_titlebar(perspective.headerbar) -- GitLab From bea8da7edc0509d60eb0c8471f56ff873bafe374 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 3 Sep 2022 20:41:36 +0530 Subject: [PATCH 070/132] Remove deprecated GdkWindowTypeHint --- data/ui/alignmentprogress.ui | 1 - data/ui/clipmediaprops.ui | 1 - data/ui/elementsettingsdialog.ui | 1 - data/ui/filelisterrordialog.ui | 1 - data/ui/preferences.ui | 1 - data/ui/projectsettings.ui | 1 - data/ui/renderingdialog.ui | 1 - data/ui/renderingprogress.ui | 1 - pitivi/editorperspective.py | 1 - pitivi/tabsmanager.py | 2 -- pitivi/viewer/viewer.py | 2 -- 11 files changed, 13 deletions(-) diff --git a/data/ui/alignmentprogress.ui b/data/ui/alignmentprogress.ui index 47928f081..dff8eb795 100644 --- a/data/ui/alignmentprogress.ui +++ b/data/ui/alignmentprogress.ui @@ -12,7 +12,6 @@ True center-on-parent 400 - dialog False diff --git a/data/ui/clipmediaprops.ui b/data/ui/clipmediaprops.ui index 563cc1637..44bfe6ba2 100644 --- a/data/ui/clipmediaprops.ui +++ b/data/ui/clipmediaprops.ui @@ -9,7 +9,6 @@ 5 5 Clip Properties - dialog True diff --git a/data/ui/elementsettingsdialog.ui b/data/ui/elementsettingsdialog.ui index 1382a037d..cc45d1484 100644 --- a/data/ui/elementsettingsdialog.ui +++ b/data/ui/elementsettingsdialog.ui @@ -6,7 +6,6 @@ False Properties for <element> True - dialog True diff --git a/data/ui/filelisterrordialog.ui b/data/ui/filelisterrordialog.ui index 2234177dc..d171747f4 100644 --- a/data/ui/filelisterrordialog.ui +++ b/data/ui/filelisterrordialog.ui @@ -5,7 +5,6 @@ True False - dialog diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index 88e1cef78..d145da1bc 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -6,7 +6,6 @@ Preferences True False - dialog diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index 086fc0d3f..a0a86e0a2 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -59,7 +59,6 @@ False Project Settings center-on-parent - dialog diff --git a/data/ui/renderingdialog.ui b/data/ui/renderingdialog.ui index dc276071a..7bfbcef2e 100644 --- a/data/ui/renderingdialog.ui +++ b/data/ui/renderingdialog.ui @@ -35,7 +35,6 @@ True center-always 220 - dialog 600 diff --git a/data/ui/renderingprogress.ui b/data/ui/renderingprogress.ui index 8228b2bc5..0f2099c49 100644 --- a/data/ui/renderingprogress.ui +++ b/data/ui/renderingprogress.ui @@ -8,7 +8,6 @@ True center-on-parent 400 - dialog diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index e35705b90..29da7dc72 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -834,7 +834,6 @@ class PreviewAssetWindow(Gtk.Window): self.app = app self.set_title(_("Preview")) - self.set_type_hint(Gdk.WindowTypeHint.UTILITY) self.set_transient_for(app.gui) self._previewer = PreviewWidget(app.settings, minimal=True) diff --git a/pitivi/tabsmanager.py b/pitivi/tabsmanager.py index c473da028..0cc20ec3c 100644 --- a/pitivi/tabsmanager.py +++ b/pitivi/tabsmanager.py @@ -15,7 +15,6 @@ # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . """Gtk.Notebook helpers.""" -from gi.repository import Gdk from gi.repository import Gtk from pitivi.settings import ConfigError @@ -94,7 +93,6 @@ class BaseTabs(Gtk.Notebook, Loggable): original_position = self.page_num(child) child_name = self.get_tab_label(child).get_text() window = Gtk.Window() - window.set_type_hint(Gdk.WindowTypeHint.UTILITY) window.set_title(child_name) # Get the previous window state settings diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 32a5f81b5..612424d5f 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -608,7 +608,6 @@ class ViewerContainer(Gtk.Box, Loggable): if widget.get_active(): self.external_window.hide() # GTK doesn't let us fullscreen utility windows - self.external_window.set_type_hint(Gdk.WindowTypeHint.NORMAL) self.external_window.show() self.external_window.fullscreen() widget.set_tooltip_text(_("Exit fullscreen mode")) @@ -616,7 +615,6 @@ class ViewerContainer(Gtk.Box, Loggable): self.external_window.unfullscreen() widget.set_tooltip_text(_("Show this window in fullscreen")) self.external_window.hide() - self.external_window.set_type_hint(Gdk.WindowTypeHint.UTILITY) self.external_window.show() def _position_cb(self, unused_pipeline, position): -- GitLab From b33682aa2e2f145a05efb775ef50a0aa3e497a52 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 3 Sep 2022 23:20:00 +0530 Subject: [PATCH 071/132] Remove deprecated no_show_all property --- pitivi/interactiveintro.py | 1 - pitivi/timeline/timeline.py | 3 --- pitivi/viewer/guidelines.py | 1 - pitivi/viewer/safe_areas_overlay.py | 2 -- 4 files changed, 7 deletions(-) diff --git a/pitivi/interactiveintro.py b/pitivi/interactiveintro.py index 73b828e2f..90e386831 100644 --- a/pitivi/interactiveintro.py +++ b/pitivi/interactiveintro.py @@ -94,7 +94,6 @@ class InteractiveIntro(GObject.Object): def __create_intro_button(self): """Creates a button for controlling the intro.""" button = Gtk.Button.new_from_icon_name("org.pitivi.Pitivi-symbolic") - button.props.no_show_all = True button.set_has_frame(False) # We could set_action_name, but we don't know here the group # in which the action will be added, so it's simpler this way. diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 9cb7c66e4..3ddba5607 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -151,7 +151,6 @@ class Marquee(Gtk.Box, Loggable): self.start_x, self.start_y = 0, 0 self.end_x, self.end_y = self.start_x, self.start_y - self.props.no_show_all = True self.hide() self.add_css_class("Marquee") @@ -405,7 +404,6 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.mini_layout_container = Gtk.Box.new() self.mini_layout_container.append(self.mini_layout) self.mini_layout_container.add_events(Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE) - self.mini_layout_container.props.no_show_all = True self.mini_layout_container.props.height_request = MINI_LAYER_HEIGHT self.mini_layout_container.hide() @@ -2649,7 +2647,6 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): if self.timeline.mini_layout_container.is_visible(): self.timeline.mini_layout_container.hide() else: - self.timeline.mini_layout_container.props.no_show_all = False self.timeline.mini_layout_container.show() def __action_locked_playhead_mode_cb(self, unused_action, unused_parameter): diff --git a/pitivi/viewer/guidelines.py b/pitivi/viewer/guidelines.py index b32e957a8..85cd9571f 100644 --- a/pitivi/viewer/guidelines.py +++ b/pitivi/viewer/guidelines.py @@ -153,7 +153,6 @@ class GuidelinesOverlay(Gtk.DrawingArea): self.active_guidelines = set() self.hide() - self.props.no_show_all = True def add_guideline(self, guideline): if guideline not in self.active_guidelines: diff --git a/pitivi/viewer/safe_areas_overlay.py b/pitivi/viewer/safe_areas_overlay.py index 339ee950f..8b77193b9 100644 --- a/pitivi/viewer/safe_areas_overlay.py +++ b/pitivi/viewer/safe_areas_overlay.py @@ -29,8 +29,6 @@ class SafeAreasOverlay(Gtk.DrawingArea): self.__project.connect("safe-area-size-changed", self.__safe_areas_size_changed_cb) - self.props.no_show_all = True - def __safe_areas_size_changed_cb(self, project): self.queue_draw() -- GitLab From fc6e2476c5e79803bca5c8508b8f929f2e557066 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 11 Sep 2022 11:13:53 +0530 Subject: [PATCH 072/132] Update medialibrary ui to GTK4 --- data/ui/medialibrary.ui | 106 ++++++++++++++-------------------------- pitivi/medialibrary.py | 13 ++--- 2 files changed, 43 insertions(+), 76 deletions(-) diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index 894848a8c..419953453 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -2,12 +2,9 @@ - True - False + center - True - False center center - True - False - Remove selected clips from the project + Remove selected clips from the project medialibrary.remove-assets - True + 1 list-remove-symbolic - media_remove_button + media_remove_button - True - False - Clip properties... - True + Clip properties... + 1 document-properties-symbolic - media_props_button + media_props_button - True - False - Show tags associated with selected clips - True + Show tags associated with selected clips + 1 tag-symbolic - tags_button + tags_button - True - False - Insert the selected clips at the end of the timeline + Insert the selected clips at the end of the timeline medialibrary.insert-assets-at-end - True + 1 insert-object-symbolic - media_insert_button + media_insert_button @@ -72,95 +61,79 @@ - True - False - True - False - Add media files to your project - Import - True + Add media files to your project + Import + 1 list-add-symbolic - media_import_button + media_import_button - True - False - Show clips as a detailed list - True + Show clips as a detailed list + 1 view-list-symbolic - media_listview_button + media_listview_button - True - True + 1 3 - True - Search... + 1 + Search... - media_search_entry + media_search_entry - medialibrary_toolbar + medialibrary_toolbar - True - False warning - True + 1 - False + 0 8 8 8 8 16 - fill - True - False - True + 1 0 - fill - False + 0 5 5 5 5 6 - fill - True - True - fill - True + 1 + 1 @@ -170,41 +143,34 @@ - True - False other - False + 0 8 8 8 8 16 - fill - True - False - Add media to your project by dragging files and folders here or by using the "Import" button. - True + Add media to your project by dragging files and folders here or by using the "Import" button. + 1 0 - True - fill + 1 - False + 0 5 5 5 5 vertical 6 - fill diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index bfc50eb5f..22d8d0bd4 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -581,6 +581,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.flowbox = Gtk.FlowBox() self.flowbox.set_valign(Gtk.Align.START) + self.flowbox.set_vexpand(True) self.flowbox.bind_model(self.store, self.create_iconview_widget_func) # Setting up respective adjustments to allow automatic scrolling self.flowbox.set_vadjustment(self.scrollwin.get_vadjustment()) @@ -644,12 +645,12 @@ class MediaLibraryWidget(Gtk.Box, Loggable): # Add all the child widgets. self.prepend(toolbar) - self.prepend(self._welcome_infobar) - self.prepend(self._project_settings_infobar) - self.prepend(self._import_warning_infobar) - self.prepend(self.scrollwin) - self.prepend(self._progressbar) - self.prepend(bottom_toolbar_container) + self.append(self._welcome_infobar) + self.append(self._project_settings_infobar) + self.append(self._import_warning_infobar) + self.append(self.scrollwin) + self.append(self._progressbar) + self.append(bottom_toolbar_container) self.filter_store() -- GitLab From 0b74089daf00e2134af71da8a280b7120f0b96b9 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 11 Sep 2022 16:53:31 +0530 Subject: [PATCH 073/132] Fix effectslibrary.ui search --- data/ui/effectslibrary.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/ui/effectslibrary.ui b/data/ui/effectslibrary.ui index f0536c38f..11dc04ae4 100644 --- a/data/ui/effectslibrary.ui +++ b/data/ui/effectslibrary.ui @@ -15,7 +15,7 @@ - + 5 1 1 -- GitLab From 5db3dc5e7041e54687be21057a9fa8c385a554e3 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 22 Sep 2022 16:30:42 +0530 Subject: [PATCH 074/132] Port project settings to GTK4 --- data/ui/projectsettings.ui | 297 +++++++++++-------------------------- pitivi/preset.py | 4 +- 2 files changed, 85 insertions(+), 216 deletions(-) diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index a0a86e0a2..c887b996c 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -1,7 +1,6 @@ - - + 1 9999 @@ -56,60 +55,24 @@ 10 - False - Project Settings - center-on-parent + Project Settings - + - True - False vertical 12 5 5 5 5 - - - True - False - fill - - - Cancel - True - True - True - - - - - OK - True - True - True - - - - - - True - False 6 12 - fill - True - False - 0 - + - True - False 12 12 18 @@ -118,41 +81,27 @@ 12 - True - False end 6 - True - False start - Preset: + Preset: - + - True - False - True - fill - - - True - - + 1 - True - True - True - False - fill + 1 + 1 + 0 open-menu-symbolic @@ -160,76 +109,56 @@ - True - False vertical 12 - fill - True - False vertical 6 - fill - True - False start - Size: + Size: - + - True - False 6 - True - True + 1 adjustment1 - True + 1 - True - False × - True - True + 1 adjustment2 - True + 1 - True - False - fill - pixels + pixels - Constrain proportions - True - True - False - Maintain aspect ratio + Constrain proportions + 1 + Maintain aspect ratio start - True @@ -237,28 +166,20 @@ - True - False start vertical 6 - fill - True - False start - Frame rate: + Frame rate: - + - True - False - fill @@ -275,12 +196,10 @@ - + - True - False - Video + Video @@ -292,14 +211,8 @@ - True - False - 0 - - + - True - False start 12 12 @@ -309,10 +222,9 @@ 6 - True - True + 1 10 - True + 1 1 @@ -322,10 +234,8 @@ - True - False start - Author: + Author: 0 0 @@ -334,10 +244,8 @@ - True - False start - Year: + Year: 2 0 @@ -346,12 +254,11 @@ - True - True + 1 start 1900 adjustment3 - True + 1 1900 3 @@ -384,12 +291,10 @@ - + - True - False - Info + Info @@ -401,13 +306,8 @@ - True - False - 0 - + - True - False 12 12 18 @@ -416,91 +316,68 @@ 12 - True - False vertical 12 - fill - True - False vertical 6 - fill - True - False start - Scaled proxies resolution: + Scaled proxies resolution: - + - True - False 6 - True - True - 1 + 1 + 1 adjustment4 - True + 1 1 - True - False × - True - True - 1 + 1 + 1 adjustment5 - True + 1 1 - True - False - fill - pixels + pixels - Constrain proportions - True - True - False + Constrain proportions + 1 start - True - True - True - <a href='#'>Proxy Preferences</a> - True - False + 1 + <a href='#'>Proxy Preferences</a> + 1 1 - fill @@ -509,12 +386,10 @@ - + - True - False - Proxy + Proxy @@ -525,14 +400,8 @@ - True - False - 0 - - + - True - False 6 6 12 @@ -541,12 +410,10 @@ 12 - True - False start - Title: + Title: - + 0 @@ -557,13 +424,11 @@ - True - False start 6 - Action: + Action: - + 0 @@ -574,11 +439,10 @@ - True - True + 1 1 adjustment8 - True + 1 1 0 @@ -588,11 +452,10 @@ - True - True + 1 1 adjustment9 - True + 1 1 2 @@ -602,11 +465,10 @@ - True - True + 1 1 adjustment6 - True + 1 1 0 @@ -616,11 +478,10 @@ - True - True + 1 1 adjustment7 - True + 1 1 2 @@ -630,8 +491,6 @@ - True - False % 0 @@ -642,8 +501,6 @@ - True - False % 0 @@ -654,8 +511,6 @@ - True - False × 1 @@ -665,8 +520,6 @@ - True - False × 1 @@ -675,12 +528,10 @@ - + - True - False - Safe Areas + Safe Areas @@ -706,5 +557,23 @@ button8 ok_button + + + + + Cancel + 1 + 1 + + + + + OK + 1 + 1 + + + + diff --git a/pitivi/preset.py b/pitivi/preset.py index aa09a6f20..af512e64d 100644 --- a/pitivi/preset.py +++ b/pitivi/preset.py @@ -113,9 +113,9 @@ class PresetManager(GObject.Object, Loggable): menu_model.append(_("Save"), "preset.%s" % action.get_name()) self.action_save = action - menu = Gtk.Menu.new_from_model(menu_model) + menu = Gtk.PopoverMenu.new_from_model(menu_model) menu.insert_action_group("preset", action_group) - button.set_popup(menu) + button.set_popover(menu) def _preset_changed_cb(self, combo): """Handles the selection of a preset.""" -- GitLab From c0130bc9c6d764ae13e58446a5f68788ce44140b Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 24 Sep 2022 23:18:02 +0530 Subject: [PATCH 075/132] Fix append and prepend order --- pitivi/effects.py | 4 ++-- pitivi/transitions.py | 6 +++--- pitivi/viewer/viewer.py | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pitivi/effects.py b/pitivi/effects.py index ae4d493d7..5baf983c3 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -504,6 +504,8 @@ class EffectListWidget(Gtk.Box, Loggable): label.set_halign(Gtk.Align.FILL) label.set_hexpand(True) + effect_box.prepend(label) + if not only_text: # Show effect thumbnail icon = Gtk.Image.new_from_pixbuf(effect_info.icon) @@ -530,8 +532,6 @@ class EffectListWidget(Gtk.Box, Loggable): fav_button.connect("clicked", self._fav_button_clicked_cb, effect_box.effect_name) effect_box.append(fav_button) - effect_box.prepend(label) - # Set up drag behavoir eventbox = Gtk.Box() eventbox.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) diff --git a/pitivi/transitions.py b/pitivi/transitions.py index 66cc742dd..4e167515c 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -137,9 +137,9 @@ class TransitionsListWidget(Gtk.Box, Loggable): GLib.idle_add(self._load_available_transitions_cb) self.prepend(self.infobar) - self.prepend(self.searchbar) - self.prepend(self.iconview_scrollwin) - self.prepend(self.props_widgets) + self.append(self.searchbar) + self.append(self.iconview_scrollwin) + self.append(self.props_widgets) self.infobar.set_revealed(True) self.iconview.hide() diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 612424d5f..bb717daba 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -309,7 +309,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.guidelines_button.set_icon_name("view-grid-symbolic") self.guidelines_button.set_has_frame(False) self.guidelines_button.set_tooltip_text(_("Select composition guidelines")) - bbox.prepend(self.guidelines_button) + bbox.append(self.guidelines_button) self.start_button = Gtk.Button.new_from_icon_name("media-skip-backward-symbolic") self.start_button.connect("clicked", self._start_button_clicked_cb) @@ -317,7 +317,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.start_button.set_tooltip_text( _("Go to the beginning of the timeline")) self.start_button.set_sensitive(False) - bbox.prepend(self.start_button) + bbox.append(self.start_button) self.back_button = Gtk.Button.new_from_icon_name("media-seek-backward-symbolic") @@ -325,11 +325,11 @@ class ViewerContainer(Gtk.Box, Loggable): self.back_button.connect("clicked", self._back_cb) self.back_button.set_tooltip_text(_("Go back one second")) self.back_button.set_sensitive(False) - bbox.prepend(self.back_button) + bbox.append(self.back_button) self.playpause_button = PlayPauseButton() self.playpause_button.connect("play", self._play_button_cb) - bbox.prepend(self.playpause_button) + bbox.append(self.playpause_button) self.playpause_button.set_sensitive(False) self.forward_button = Gtk.Button.new_from_icon_name("media-seek-forward-symbolic") @@ -337,7 +337,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.forward_button.connect("clicked", self._forward_cb) self.forward_button.set_tooltip_text(_("Go forward one second")) self.forward_button.set_sensitive(False) - bbox.prepend(self.forward_button) + bbox.append(self.forward_button) self.end_button = Gtk.Button.new_from_icon_name("media-skip-forward-symbolic") self.end_button.set_has_frame(False) @@ -345,7 +345,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.end_button.set_tooltip_text( _("Go to the end of the timeline")) self.end_button.set_sensitive(False) - bbox.prepend(self.end_button) + bbox.append(self.end_button) self.timecode_entry = TimeWidget() self.timecode_entry.set_widget_value(0) @@ -359,7 +359,7 @@ class ViewerContainer(Gtk.Box, Loggable): timecode_eventcontroller_key = Gtk.EventControllerKey() timecode_eventcontroller_key.connect("key_pressed", self._entry_key_press_event_cb) self.timecode_entry.add_controller(timecode_eventcontroller_key) - bbox.prepend(self.timecode_entry) + bbox.append(self.timecode_entry) self.undock_button = Gtk.Button.new_from_icon_name("view-restore-symbolic") @@ -367,7 +367,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.undock_button.connect("clicked", self.undock_cb) self.undock_button.set_tooltip_text( _("Detach the viewer\nYou can re-attach it by closing the newly created window.")) - bbox.prepend(self.undock_button) + bbox.append(self.undock_button) self.show() -- GitLab From c66a97e5956a1204f9a0fa4a92cc7b6a206f1114 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 24 Sep 2022 23:30:06 +0530 Subject: [PATCH 076/132] Hide MediaLibrary progressbar by default --- pitivi/medialibrary.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 22d8d0bd4..566ddcc94 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -601,6 +601,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): # The _progressbar that shows up when importing clips self._progressbar = Gtk.ProgressBar() self._progressbar.set_show_text(True) + self._progressbar.hide() # Connect to project. We must remove and reset the callbacks when # changing project. -- GitLab From 5e09a7bf120a318761ce08abb922feeb201bf0d5 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 25 Sep 2022 17:53:21 +0530 Subject: [PATCH 077/132] Remove deprecated add_with_viewport --- pitivi/dialogs/prefs.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 06bdbf8fb..900a6267f 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -420,14 +420,11 @@ class PreferencesDialog(Loggable): self.content_box.props.halign = Gtk.Align.CENTER self.content_box.add_css_class('prefs_list') - viewport = Gtk.Viewport() - viewport.set_child(self.content_box) - scrolled_window = Gtk.ScrolledWindow() scrolled_window.props.hexpand = True scrolled_window.props.min_content_height = 500 scrolled_window.props.min_content_width = 600 - scrolled_window.add_with_viewport(viewport) + scrolled_window.set_child(self.content_box) outside_box = Gtk.Box() outside_box.append(scrolled_window) -- GitLab From 56ad84b6033a9911c1ce17ec35f7bcae75f485a8 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 25 Sep 2022 18:01:02 +0530 Subject: [PATCH 078/132] Remove deprecated stock_size along with iconview prepend --- pitivi/transitions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pitivi/transitions.py b/pitivi/transitions.py index 4e167515c..a88517bb3 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -120,8 +120,8 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.iconview = Gtk.IconView(model=self.model_filter) cell_renderer = Gtk.CellRendererPixbuf() - cell_renderer.props.stock_size = Gtk.IconSize.LARGE - self.iconview.prepend(cell_renderer) + cell_renderer.props.icon_size = Gtk.IconSize.LARGE + self.iconview.pack_end(cell_renderer, False) self.iconview.add_attribute(cell_renderer, "icon-name", COL_ICON_NAME) self.iconview.set_item_width(48 + SPACING) -- GitLab From b25ab3345a8d37b13c0999b668f24fca9e337921 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 25 Sep 2022 18:15:29 +0530 Subject: [PATCH 079/132] Replace deprecated grid add --- pitivi/utils/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 132a8606b..030d73ed0 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -1236,9 +1236,9 @@ class ZoomBox(Gtk.Grid, Zoomable): zoom_fit_btn.set_tooltip_text(_("Zoom Fit")) zoom_fit_btn_grid = Gtk.Grid() zoom_fit_icon = Gtk.Image.new_from_icon_name("zoom-fit-best-symbolic") - zoom_fit_btn_grid.add(zoom_fit_icon) + zoom_fit_btn_grid.attach(zoom_fit_icon, 0, 0, 1, 1) zoom_fit_btn_label = Gtk.Label.new(_("Zoom")) - zoom_fit_btn_grid.add(zoom_fit_btn_label) + zoom_fit_btn_grid.attach(zoom_fit_btn_label, 1, 0, 1, 1) zoom_fit_btn_grid.set_column_spacing(SPACING / 2) zoom_fit_btn.set_child(zoom_fit_btn_grid) zoom_fit_btn.connect("clicked", self._zoom_fit_cb) -- GitLab From bc029422db0094268fe9e7c0278c65a7cd4c5c2b Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 2 Oct 2022 14:36:56 +0530 Subject: [PATCH 080/132] Use GtkPicture for custom sized images --- data/ui/project_info.ui | 3 ++- pitivi/clipproperties.py | 2 +- pitivi/dialogs/missingasset.py | 3 ++- pitivi/effects.py | 9 +++++---- pitivi/greeterperspective.py | 2 +- pitivi/medialibrary.py | 6 ++++-- pitivi/timeline/previewers.py | 10 +++++----- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/data/ui/project_info.ui b/data/ui/project_info.ui index dd9901f0c..cf20fac06 100644 --- a/data/ui/project_info.ui +++ b/data/ui/project_info.ui @@ -27,11 +27,12 @@ vertical fill - + True False center True + False diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index 8e607d9ce..cdbc3c2f8 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -704,7 +704,7 @@ class EffectProperties(Gtk.Expander, Loggable): remove_effect_button.props.margin_end = PADDING row_widgets_box = Gtk.Box() - row_drag_icon = Gtk.Image.new_from_pixbuf(self.drag_lines_pixbuf) + row_drag_icon = Gtk.Picture.new_for_pixbuf(self.drag_lines_pixbuf) row_drag_icon.props.margin_top = PADDING row_drag_icon.props.margin_bottom = PADDING row_drag_icon.props.margin_start = PADDING diff --git a/pitivi/dialogs/missingasset.py b/pitivi/dialogs/missingasset.py index bb14b7ca7..a0df7e97e 100644 --- a/pitivi/dialogs/missingasset.py +++ b/pitivi/dialogs/missingasset.py @@ -76,7 +76,8 @@ class MissingAssetDialog(Gtk.Dialog, Loggable): unused_small_thumb, large_thumb = AssetThumbnail.get_thumbnails_from_xdg_cache(uri) if large_thumb: self.debug("A thumbnail file was found for %s", uri) - thumbnail = Gtk.Image.new_from_pixbuf(large_thumb) + thumbnail = Gtk.Picture.new_for_pixbuf(large_thumb) + thumbnail.set_can_shrink(False) hbox.append(thumbnail) vbox.prepend(hbox) diff --git a/pitivi/effects.py b/pitivi/effects.py index 5baf983c3..c3fb18204 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -397,7 +397,7 @@ class EffectListWidget(Gtk.Box, Loggable): toolbar = builder.get_object("effectslibrary_box") self.search_entry = builder.get_object("search_entry") self.fav_view_toggle = builder.get_object("favourites_toggle") - self.fav_view_toggle.set_child(Gtk.Image.new_from_pixbuf(self._star_icon_solid)) + self.fav_view_toggle.set_child(Gtk.Picture.new_for_pixbuf(self._star_icon_solid)) self.main_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) @@ -508,7 +508,8 @@ class EffectListWidget(Gtk.Box, Loggable): if not only_text: # Show effect thumbnail - icon = Gtk.Image.new_from_pixbuf(effect_info.icon) + icon = Gtk.Picture.new_for_pixbuf(effect_info.icon) + icon.set_can_shrink(False) icon.props.margin_top = SPACING / 2 icon.props.margin_bottom = SPACING / 2 icon.props.margin_start = SPACING / 2 @@ -594,9 +595,9 @@ class EffectListWidget(Gtk.Box, Loggable): button.active = is_active if button.active: - image = Gtk.Image.new_from_pixbuf(self._star_icon_solid) + image = Gtk.Picture.new_for_pixbuf(self._star_icon_solid) else: - image = Gtk.Image.new_from_pixbuf(self._star_icon_regular) + image = Gtk.Picture.new_for_pixbuf(self._star_icon_regular) button.set_child(image) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 6a512fede..c3c23ee23 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -74,7 +74,7 @@ class ProjectInfoRow(Gtk.ListBoxRow): beautify_last_updated_timestamp(recent_project_item.get_modified().to_unix())) def __load_thumb_cb(self): - self.__thumb.set_from_pixbuf(Project.get_thumb(self.uri)) + self.__thumb.set_pixbuf(Project.get_thumb(self.uri)) return False diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 566ddcc94..e1a76ec0b 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -663,7 +663,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable): box.props.margin_start = PADDING / 2 box.props.margin_end = PADDING / 2 - icon = Gtk.Image.new_from_pixbuf(item.icon_128) + icon = Gtk.Picture.new_for_pixbuf(item.icon_128) + icon.set_can_shrink(False) box.prepend(icon) box.set_tooltip_markup(item.infotext) @@ -678,7 +679,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable): box.props.margin_end = PADDING box.set_spacing(SPACING) - icon = Gtk.Image.new_from_pixbuf(item.icon_64) + icon = Gtk.Picture.new_for_pixbuf(item.icon_64) + icon.set_can_shrink(False) label = Gtk.Label() label.props.ellipsize = Pango.EllipsizeMode.START diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py index 57aa37f38..3b315c826 100644 --- a/pitivi/timeline/previewers.py +++ b/pitivi/timeline/previewers.py @@ -504,7 +504,7 @@ class ImagePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): self.put(thumb, x, y) thumbs[position] = thumb - thumb.set_from_pixbuf(self.__image_pixbuf) + thumb.set_pixbuf(self.__image_pixbuf) thumb.set_visible(True) for thumb in self.thumbs.values(): @@ -903,7 +903,7 @@ class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable): thumbs[position] = thumb if position in self.thumb_cache: pixbuf = self.thumb_cache[position] - thumb.set_from_pixbuf(pixbuf) + thumb.set_pixbuf(pixbuf) thumb.set_visible(True) else: if position not in self.failures and position != self.position: @@ -925,7 +925,7 @@ class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable): # Can happen because we don't stop the pipeline before # updating the thumbnails in _update_thumbnails. return - thumb.set_from_pixbuf(pixbuf) + thumb.set_pixbuf(pixbuf) def release(self): """Stops preview generation and cleans the object.""" @@ -950,11 +950,11 @@ class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable): self._update_thumbnails() -class Thumbnail(Gtk.Image): +class Thumbnail(Gtk.Picture): """Simple widget representing a Thumbnail.""" def __init__(self, width, height): - Gtk.Image.__init__(self) + Gtk.Picture.__init__(self) self.add_css_class("Thumbnail") -- GitLab From 64e6e579c0ead426704d313bc46215191f492aba Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 23 Oct 2022 01:34:43 +0530 Subject: [PATCH 081/132] Update preferences to GTK4 --- data/ui/preferences.ui | 82 ++++++++++++++--------------------------- pitivi/dialogs/prefs.py | 17 +++++---- pitivi/mainwindow.py | 3 +- 3 files changed, 38 insertions(+), 64 deletions(-) diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index d145da1bc..6b070f324 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -2,49 +2,35 @@ - False - Preferences - True - False - + Preferences + 1 + 0 - + - False vertical 8 - True - False - True - False - True + 1 stack - True - fill + 1 - True - False vertical - True - fill + 1 - True - False - True - fill + 1 crossfade @@ -55,38 +41,33 @@ - False + 0 warning - fill - False + 0 8 8 8 8 - True - False - Some changes will not take effect until you restart Pitivi - True - True - fill + Some changes will not take effect until you restart Pitivi + 1 + 1 - False + 0 5 5 5 5 vertical 6 - fill @@ -96,39 +77,32 @@ - False - fill + end - Reset to Factory Settings - True - False - True - True - fill - Reset all settings to their default values + Reset to Factory Settings + 0 + 1 + 1 + Reset all settings to their default values - Revert - True - False - True - True - Revert all settings to the previous values (before you opened the preferences dialog) + Revert + 0 + 1 + 1 + Revert all settings to the previous values (before you opened the preferences dialog) - fill - Close - True - True - True - fill + Close + 1 + 1 diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 900a6267f..48393b068 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -253,11 +253,12 @@ class PreferencesDialog(Loggable): label_widget = Gtk.Label.new(label) label_widget.set_yalign(0.5) + label_widget.set_xalign(0) label_widget.props.margin_end = PADDING * 3 label_widget.props.margin_top = PADDING * 2 label_widget.props.margin_bottom = PADDING * 2 label_widget.set_hexpand(True) - label_widget.set_halign(Gtk.Align.FILL) + label_widget.set_halign(Gtk.Align.START) label_size_group.add_widget(label_widget) widget.props.margin_end = PADDING * 3 @@ -266,14 +267,14 @@ class PreferencesDialog(Loggable): prop_size_group.add_widget(widget) box.prepend(label_widget) - box.prepend(widget) + box.append(widget) if revert_widget: - box.prepend(revert_widget) + box.append(revert_widget) if extra_widget: box1 = box box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - box.prepend(box1) + box.append(box1) extra_widget.props.margin_top = SPACING extra_widget.props.margin_bottom = SPACING extra_widget.props.margin_start = SPACING @@ -479,8 +480,8 @@ class PreferencesDialog(Loggable): # Pack the three widgets above into a row and add to parent_box. contents_box = Gtk.Box() contents_box.prepend(title_label) - contents_box.prepend(accel_label) - contents_box.prepend(button) + contents_box.append(accel_label) + contents_box.append(button) return contents_box @@ -948,8 +949,8 @@ class PluginPreferencesPage(Gtk.ScrolledWindow): self.set_min_content_width(600) wrapper_box.prepend(self._infobar_revealer) - wrapper_box.prepend(plugins_box) - wrapper_box.prepend(note_label) + wrapper_box.append(plugins_box) + wrapper_box.append(note_label) # Helpers self._infobar_timer = None diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index dd8ecf6fc..8216cfdeb 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -225,8 +225,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): def __preferences_cb(self, unused_action, unused_param): dialog = PreferencesDialog(self.app) - dialog.set_modal(True) - dialog.show() + dialog.run() def __configure_cb(self, unused_widget, unused_event): """Saves the main window size.""" -- GitLab From 334aa0d71f6609ef9c778ee528fee2da02945c04 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 11 Nov 2022 15:36:03 +0530 Subject: [PATCH 082/132] Fix margin in project settings and preferences --- data/ui/preferences.ui | 7 +++++++ data/ui/projectsettings.ui | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index 6b070f324..db6b43d2f 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -78,9 +78,14 @@ end + 5 + 5 + 5 + 5 Reset to Factory Settings + 5 0 1 1 @@ -91,6 +96,7 @@ Revert + 5 0 1 1 @@ -101,6 +107,7 @@ Close + 5 1 1 diff --git a/data/ui/projectsettings.ui b/data/ui/projectsettings.ui index c887b996c..447bed648 100644 --- a/data/ui/projectsettings.ui +++ b/data/ui/projectsettings.ui @@ -559,11 +559,16 @@ + 5 + 5 + 5 + 5 Cancel 1 1 + 5 -- GitLab From 0f48ea2dfa5f3eccfe0dafc1873c92572ecb8ef2 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Thu, 24 Nov 2022 16:21:24 +0530 Subject: [PATCH 083/132] Remove style context from get_color function --- pitivi/utils/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index 85bd48f74..5f54637d0 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -434,7 +434,7 @@ def format_audiochannels(channels): def gtk_style_context_get_color(context, state): context.save() context.set_state(state) - color = context.get_color(context.get_state()) + color = context.get_color() context.restore() return color -- GitLab From 5cb2293c90814882d338ec6eb428720f2548ce54 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 25 Dec 2022 19:44:07 +0530 Subject: [PATCH 084/132] Fix GtkInfobar content and action not visible --- data/ui/medialibrary.ui | 4 ---- data/ui/preferences.ui | 2 -- 2 files changed, 6 deletions(-) diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index 419953453..46bb6e161 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -108,7 +108,6 @@ 1 - 0 8 8 8 @@ -124,7 +123,6 @@ - 0 5 5 5 @@ -146,7 +144,6 @@ other - 0 8 8 8 @@ -164,7 +161,6 @@ - 0 5 5 5 diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui index db6b43d2f..dab370952 100644 --- a/data/ui/preferences.ui +++ b/data/ui/preferences.ui @@ -45,7 +45,6 @@ warning - 0 8 8 8 @@ -61,7 +60,6 @@ - 0 5 5 5 -- GitLab From 130cfc8943fd1dc6fab2c942787931fc58698945 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 25 Dec 2022 20:44:34 +0530 Subject: [PATCH 085/132] Fix tags GtkPopover --- data/ui/medialibrary.ui | 4 ++-- pitivi/medialibrary.py | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui index 46bb6e161..0e150670a 100644 --- a/data/ui/medialibrary.ui +++ b/data/ui/medialibrary.ui @@ -33,11 +33,11 @@ - + Show tags associated with selected clips 1 tag-symbolic - + tags_button diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index e1a76ec0b..ac8cea5c4 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -1261,13 +1261,13 @@ class MediaLibraryWidget(Gtk.Box, Loggable): popover_heading.props.margin_start = SPACING popover_heading.props.margin_end = SPACING box.append(popover_heading) - box.prepend(tags_list) - box.prepend(new_entry_box) + box.append(tags_list) + box.append(new_entry_box) self.tags_popover.connect("closed", self._tags_popover_closed_cb, tags_list, tagstore) self.tags_popover.set_child(box) self.tags_popover.set_position(Gtk.PositionType.BOTTOM) - self.tags_popover.set_relative_to(self.tags_button) + self.tags_button.set_popover(self.tags_popover) self.tags_popover.popup() tags_list.unselect_all() @@ -1288,14 +1288,13 @@ class MediaLibraryWidget(Gtk.Box, Loggable): checkbutton.connect("toggled", self._tag_toggled_cb, tag_item) - box.append(checkbutton) + box.set_child(checkbutton) return box def _tags_popover_closed_cb(self, popover, tags_list, tagstore): self.apply_changed_tags(tags_list, tagstore) popover.hide() - self.tags_button.set_active(False) self.tags_popover = None def _tag_toggled_cb(self, toggle_button, tag_item): -- GitLab From 3f6cf9ecc6ed209e6a5de50ca8e47971cfa57b42 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Tue, 27 Dec 2022 00:58:50 +0530 Subject: [PATCH 086/132] Fix viewer corner DrawingArea --- pitivi/viewer/viewer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index bb717daba..92e0c618a 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -268,7 +268,7 @@ class ViewerContainer(Gtk.Box, Loggable): eventcontroller_click = Gtk.GestureClick() eventcontroller_motion = Gtk.EventControllerMotion() - corner.connect("draw", self.__corner_draw_cb, lines, space, margin) + corner.set_draw_func(self.__corner_draw_cb, lines, space, margin) eventcontroller_motion.connect("enter", self.__corner_enter_notify_cb) eventcontroller_click.connect("pressed", self.__corner_button_press_cb, hpane, vpane) eventcontroller_click.connect("released", self.__corner_button_release_cb) @@ -303,7 +303,7 @@ class ViewerContainer(Gtk.Box, Loggable): bbox.set_property("halign", Gtk.Align.CENTER) bbox.set_margin_start(SPACING) bbox.set_margin_end(SPACING) - self.append(bbox) + self.prepend(bbox) self.guidelines_button = Gtk.MenuButton.new() self.guidelines_button.set_icon_name("view-grid-symbolic") @@ -424,7 +424,7 @@ class ViewerContainer(Gtk.Box, Loggable): for count, peak in enumerate(peak_values): self.peak_meters[count].update_peakmeter(peak) - def __corner_draw_cb(self, unused_widget, cr, lines, space, margin): + def __corner_draw_cb(self, unused_widget, cr, width, height, lines, space, margin): cr.set_line_width(1) marker_color = self.app.gui.get_style_context().lookup_color("borders") -- GitLab From eb5e0a9258e61c0ecbcb0632390f0fa77dd11f33 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 7 Jan 2023 23:08:17 +0530 Subject: [PATCH 087/132] Fix peak meter --- pitivi/viewer/peak_meter.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pitivi/viewer/peak_meter.py b/pitivi/viewer/peak_meter.py index ff32f3d47..639e0ad84 100644 --- a/pitivi/viewer/peak_meter.py +++ b/pitivi/viewer/peak_meter.py @@ -48,14 +48,14 @@ class PeakMeterWidget(Gtk.DrawingArea): self.pixel_buffer = None self.add_css_class("background") - self.connect("size-allocate", self.__size_allocate_cb) + self.connect("resize", self.__resize_cb) - def __size_allocate_cb(self, unused_event, allocation): + def __resize_cb(self, unused_widget, width, height): if self.pixel_buffer is not None: self.pixel_buffer.finish() self.pixel_buffer = None - self.pixel_buffer = cairo.ImageSurface(cairo.FORMAT_ARGB32, allocation.width, allocation.height) + self.pixel_buffer = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) def draw_background(self, context, width, height): style_context = self.get_style_context() @@ -75,9 +75,11 @@ class PeakMeter(PeakMeterWidget): self.add_css_class("frame") - self.connect("size-allocate", self.__size_allocate_cb) + self.set_draw_func(self.do_draw) - def do_draw(self, context): + self.connect("resize", self.__resize_cb) + + def do_draw(self, widget, context, width, height): if self.pixel_buffer is None: return @@ -95,8 +97,8 @@ class PeakMeter(PeakMeterWidget): context.set_source_surface(pixel_buffer, 0.0, 0.0) context.paint() - def __size_allocate_cb(self, unused_event, allocation): - self.__set_gradients(allocation.width, allocation.height) + def __resize_cb(self, unused_widget, width, height): + self.__set_gradients(width, height) def __draw_bar(self, context, width, height): peak_height = self.__normalize_peak(height) @@ -150,8 +152,9 @@ class PeakMeterScale(PeakMeterWidget): PeakMeterWidget.__init__(self) width = FONT_SIZE * 2 self.set_property("width_request", width) + self.set_draw_func(self.do_draw) - def do_draw(self, context): + def do_draw(self, widget, context, width, height): if self.pixel_buffer is None: return -- GitLab From e7a305f4f8a14b90d695a23380cd6ade2389aee3 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 7 Jan 2023 23:26:38 +0530 Subject: [PATCH 088/132] Fix Ruler --- pitivi/timeline/ruler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pitivi/timeline/ruler.py b/pitivi/timeline/ruler.py index 4f90baacd..c10aac831 100644 --- a/pitivi/timeline/ruler.py +++ b/pitivi/timeline/ruler.py @@ -122,6 +122,8 @@ class ScaleRuler(Gtk.DrawingArea, Loggable): Gtk.Settings.get_default().connect("notify::gtk-theme-name", self._update_colors_cb) Gtk.Settings.get_default().connect("notify::gtk-application-prefer-dark-theme", self._update_colors_cb) + self.set_draw_func(self.do_draw) + def set_pipeline(self, pipeline): self._pipeline = pipeline self.ges_timeline = pipeline.props.timeline @@ -157,9 +159,7 @@ class ScaleRuler(Gtk.DrawingArea, Loggable): # Gtk.Widget overrides - def do_configure_event(self, unused_event): - width = self.get_allocated_width() - height = self.get_allocated_height() + def do_resize(self, width, height): self.debug("Configuring, height %d, width %d", width, height) # Destroy previous buffer @@ -173,7 +173,7 @@ class ScaleRuler(Gtk.DrawingArea, Loggable): self._set_colors() return False - def do_draw(self, context): + def do_draw(self, unused_widget, context, width, height): if self.pixbuf is None: self.info("No buffer to paint") return False -- GitLab From 5b64ff7b4fdf18565c200f7a839c99d6d0a1599d Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sun, 8 Jan 2023 03:02:42 +0530 Subject: [PATCH 089/132] Reposition Timeline toolbar to bottom --- data/ui/timelinetoolbar.ui | 4 ++-- pitivi/timeline/timeline.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/ui/timelinetoolbar.ui b/data/ui/timelinetoolbar.ui index e00d66d65..0f25a3e29 100644 --- a/data/ui/timelinetoolbar.ui +++ b/data/ui/timelinetoolbar.ui @@ -4,8 +4,8 @@ False - start - vertical + center + horizontal diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 3ddba5607..9b0fe680c 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -1893,7 +1893,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): self.attach(self.timeline, 0, 2, 2, 1) self.attach(self.vscrollbar, 2, 2, 1, 1) self.attach(hscrollbar, 1, 3, 1, 1) - self.attach(self.toolbar, 3, 2, 1, 1) + self.attach(self.toolbar, 1, 4, 1, 1) self.set_margin_top(SPACING) -- GitLab From 5a50f33b3b13da16680a2e884c8573a4308aaf6d Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 13 Jan 2023 22:08:51 +0530 Subject: [PATCH 090/132] Use custom FileChooserDialog using FileChooserWidget --- pitivi/medialibrary.py | 78 ++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index ac8cea5c4..caaeddde7 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -44,7 +44,6 @@ from pitivi.configure import get_pixmap_dir from pitivi.configure import get_ui_dir from pitivi.dialogs.clipmediaprops import ClipMediaPropsDialog from pitivi.dialogs.filelisterrordialog import FileListErrorDialog -from pitivi.mediafilespreviewer import PreviewWidget from pitivi.settings import GlobalSettings from pitivi.timeline.previewers import AssetPreviewer from pitivi.utils.loggable import Loggable @@ -58,13 +57,15 @@ from pitivi.utils.proxy import ProxyingStrategy from pitivi.utils.ui import beautify_asset from pitivi.utils.ui import beautify_eta from pitivi.utils.ui import FILE_TARGET_ENTRY -from pitivi.utils.ui import filter_unsupported_media_files from pitivi.utils.ui import info_name from pitivi.utils.ui import LARGE_THUMB_WIDTH from pitivi.utils.ui import PADDING from pitivi.utils.ui import SMALL_THUMB_WIDTH from pitivi.utils.ui import SPACING from pitivi.utils.ui import URI_TARGET_ENTRY +# ToDo: Fix Import Dialog PreviewWidget and filter +# from pitivi.mediafilespreviewer import PreviewWidget +# from pitivi.utils.ui import filter_unsupported_media_files class ViewType(IntEnum): @@ -191,17 +192,17 @@ class FileChooserExtraWidget(Gtk.Box, Loggable): proxy_box.props.margin_end = SPACING * 2 hq_proxy_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - hq_proxy_row.prepend(self.hq_proxy_check) - hq_proxy_row.prepend(self.hq_combo) - hq_proxy_row.prepend(self.help_button) - proxy_box.prepend(hq_proxy_row) + hq_proxy_row.append(self.hq_proxy_check) + hq_proxy_row.append(self.hq_combo) + hq_proxy_row.append(self.help_button) + proxy_box.append(hq_proxy_row) row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - row.prepend(self.scaled_proxy_check) - row.prepend(self.project_settings_label) - proxy_box.prepend(row) + row.append(self.scaled_proxy_check) + row.append(self.project_settings_label) + proxy_box.append(row) - self.prepend(proxy_box) + self.append(proxy_box) size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.VERTICAL) size_group.add_widget(self.__keep_open_check) @@ -807,46 +808,62 @@ class MediaLibraryWidget(Gtk.Box, Loggable): def show_import_assets_dialog(self): """Pops up the "Import Sources" dialog box.""" - dialog = Gtk.FileChooserDialog() + dialog = Gtk.Dialog() dialog.set_title(_("Select One or More Files")) - dialog.set_action(Gtk.FileChooserAction.OPEN) dialog.set_icon_name("pitivi") dialog.add_buttons(_("Cancel"), Gtk.ResponseType.CANCEL, _("Add"), Gtk.ResponseType.OK) - dialog.props.extra_widget = FileChooserExtraWidget(self.app) dialog.set_default_response(Gtk.ResponseType.OK) - dialog.set_select_multiple(True) dialog.set_modal(True) dialog.set_transient_for(self.app.gui) - dialog.set_current_folder(self.app.settings.lastImportFolder) - dialog.connect('response', self._import_dialog_box_response_cb) - previewer = PreviewWidget(self.app.settings) - dialog.set_preview_widget(previewer) - dialog.set_use_preview_label(False) - dialog.connect('update-preview', previewer.update_preview_cb) + # previewer = PreviewWidget(self.app.settings) + # dialog.set_preview_widget(previewer) + # dialog.set_use_preview_label(False) + # dialog.connect('update-preview', previewer.update_preview_cb) + + filechooserwidget = Gtk.FileChooserWidget() + filechooserwidget.set_hexpand(True) + filechooserwidget.set_vexpand(True) + filechooserwidget.set_action(Gtk.FileChooserAction.OPEN) + filechooserwidget.set_select_multiple(True) + lastfolder = Gio.File.new_for_path(self.app.settings.lastImportFolder) + filechooserwidget.set_current_folder(lastfolder) + + hbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) # Filter for the "known good" formats by default file_filter = Gtk.FileFilter() file_filter.set_name(_("Supported file formats")) - file_filter.add_custom(Gtk.FileFilterFlags.URI | Gtk.FileFilterFlags.MIME_TYPE, - filter_unsupported_media_files) + # file_filter.add_custom(Gtk.FileFilterFlags.URI | Gtk.FileFilterFlags.MIME_TYPE, + # filter_unsupported_media_files) for formatter in GES.list_assets(GES.Formatter): for extension in formatter.get_meta("extension").split(","): if not extension: continue file_filter.add_pattern("*.%s" % extension) - dialog.add_filter(file_filter) + filechooserwidget.add_filter(file_filter) # ...and allow the user to override our whitelists default = Gtk.FileFilter() default.set_name(_("All files")) default.add_pattern("*") - dialog.add_filter(default) + filechooserwidget.add_filter(default) + + extra_widgets = FileChooserExtraWidget(self.app) + hbox.prepend(filechooserwidget) + hbox.append(extra_widgets) + + dialog.connect('response', self._import_dialog_box_response_cb, filechooserwidget, extra_widgets) + + # stuff the hbox in the dialog + content_area = dialog.get_content_area() + content_area.prepend(hbox) # Add a shortcut for the project folder (if saved) if self._project.uri: shortcut = os.path.dirname(self._project.uri) - dialog.add_shortcut_folder_uri(shortcut) + shortcut_gfile = Gio.File.new_for_uri(shortcut) + filechooserwidget.add_shortcut_folder(shortcut_gfile) dialog.show() @@ -1089,16 +1106,17 @@ class MediaLibraryWidget(Gtk.Box, Loggable): # Import Sources Dialog Box callbacks - def _import_dialog_box_response_cb(self, dialogbox, response): + def _import_dialog_box_response_cb(self, dialogbox, response, filechooserwidget, extra_widgets): self.debug("response: %r", response) if response == Gtk.ResponseType.OK: - lastfolder = dialogbox.get_current_folder() + lastfolder = filechooserwidget.get_current_folder() # get_current_folder() is None if file was chosen from 'Recents' if not lastfolder: - lastfolder = GLib.path_get_dirname(dialogbox.get_filename()) + lastfolder = GLib.path_get_dirname(filechooserwidget.get_filename()) self.app.settings.lastImportFolder = lastfolder - dialogbox.props.extra_widget.save_values() - filenames = dialogbox.get_uris() + extra_widgets.save_values() + gfile = filechooserwidget.get_file() + filenames = gfile.get_uri() self._project.add_uris(filenames) if self.app.settings.closeImportDialog: dialogbox.destroy() -- GitLab From 6f3d51d84f8542f51047c52fa722c5973580a78a Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 14 Jan 2023 00:57:45 +0530 Subject: [PATCH 091/132] Set GtkPaned shrink to False --- pitivi/editorperspective.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 29da7dc72..b8db591d4 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -192,9 +192,15 @@ class EditorPerspective(Perspective, Loggable): self.mainhpaned = Gtk.Paned(orientation=Gtk.Orientation.HORIZONTAL) # Separates the two sets of tabs self.secondhpaned = Gtk.Paned(orientation=Gtk.Orientation.HORIZONTAL) + self.toplevel_widget.set_shrink_start_child(False) + self.toplevel_widget.set_shrink_end_child(False) self.toplevel_widget.set_start_child(self.mainhpaned) self.mainhpaned.set_start_child(self.secondhpaned) self.mainhpaned.set_resize_start_child(True) + self.mainhpaned.set_shrink_start_child(False) + self.mainhpaned.set_shrink_end_child(False) + self.secondhpaned.set_shrink_start_child(False) + self.secondhpaned.set_shrink_end_child(False) self.toplevel_widget.show() self.secondhpaned.show() self.mainhpaned.show() @@ -236,6 +242,8 @@ class EditorPerspective(Perspective, Loggable): # Now, the lower part: the timeline self.timelinepaned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) + self.timelinepaned.set_shrink_start_child(False) + self.timelinepaned.set_shrink_end_child(False) self.timeline_ui = TimelineContainer(self.app, self.editor_state) self.mini_timeline_ui = self.timeline_ui.timeline.mini_layout_container -- GitLab From 35035aab28f1901385d31d47e21bbbb4f6065dbb Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Sat, 14 Jan 2023 01:09:45 +0530 Subject: [PATCH 092/132] Hide Viewer frame and fix Viewer order --- pitivi/viewer/viewer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 92e0c618a..c5aba7539 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -303,7 +303,7 @@ class ViewerContainer(Gtk.Box, Loggable): bbox.set_property("halign", Gtk.Align.CENTER) bbox.set_margin_start(SPACING) bbox.set_margin_end(SPACING) - self.prepend(bbox) + self.append(bbox) self.guidelines_button = Gtk.MenuButton.new() self.guidelines_button.set_icon_name("view-grid-symbolic") @@ -373,6 +373,7 @@ class ViewerContainer(Gtk.Box, Loggable): # Create a hidden container for the clip trim preview video widget. self.hidden_chest = Gtk.Frame() + self.hidden_chest.hide() # It has to be added to the window, otherwise when we add # a video widget to it, it will create a new window! self.append(self.hidden_chest) -- GitLab From 4e1f2e71c06f79723b3eefcba500b6ee61b4d990 Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Fri, 17 Feb 2023 03:57:46 +0530 Subject: [PATCH 093/132] Fix undo redo buttons position --- pitivi/editorperspective.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index b8db591d4..e7546995a 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -325,7 +325,6 @@ class EditorPerspective(Perspective, Loggable): headerbar = Gtk.HeaderBar() undo_button = Gtk.Button.new_from_icon_name("edit-undo-symbolic") - undo_button.set_label(_("Undo")) undo_button.set_action_name("app.undo") undo_button.set_use_underline(True) @@ -347,7 +346,7 @@ class EditorPerspective(Perspective, Loggable): undo_redo_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0) undo_redo_box.add_css_class("linked") undo_redo_box.prepend(undo_button) - undo_redo_box.prepend(redo_button) + undo_redo_box.append(redo_button) headerbar.pack_start(undo_redo_box) self.builder.add_from_file( -- GitLab From 6cfa5c19fa21e8be90d6ca45e59d41df033bd70e Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 1 Mar 2023 18:41:23 +0530 Subject: [PATCH 094/132] Use callback on save as dialog --- pitivi/editorperspective.py | 43 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index e7546995a..55c9e40ee 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -586,7 +586,9 @@ class EditorPerspective(Perspective, Loggable): if project.uri is not None and project_manager.disable_save is False: res = self.app.project_manager.save_project() else: - res = self.save_project_as() + # FixMe: Remains from switching to a callback model for save as dialog + # res = self.save_project_as() + res = True elif response == Gtk.ResponseType.REJECT: res = True else: @@ -728,10 +730,7 @@ class EditorPerspective(Perspective, Loggable): return ret def save_project_as(self): - uri = self._show_save_as_dialog() - if uri is None: - return False - return self.app.project_manager.save_project(uri) + self._show_save_as_dialog() def _show_save_as_dialog(self): self.log("Save URI requested") @@ -750,38 +749,40 @@ class EditorPerspective(Perspective, Loggable): chooser.set_select_multiple(False) chooser.set_current_name(_("Untitled") + "." + asset.get_meta(GES.META_FORMATTER_EXTENSION)) - chooser.set_current_folder(self.settings.lastProjectFolder) - chooser.props.do_overwrite_confirmation = True + lastfolder = Gio.File.new_for_path(self.settings.lastProjectFolder) + chooser.set_current_folder(lastfolder) default = Gtk.FileFilter() default.set_name(_("Detect automatically")) default.add_pattern("*") chooser.add_filter(default) - response = chooser.run() + chooser.connect('response', self._save_as_dialog_response_cb) + + chooser.show() + + def __save_frame_cb(self, unused_action, unused_param): + """Exports a snapshot of the current frame as an image file.""" + res = self._show_save_screenshot_dialog() + if res: + path, mime = res[0], res[1] + self.app.project_manager.current_project.pipeline.save_thumbnail( + -1, -1, mime, path) + + def _save_as_dialog_response_cb(self, chooser, response): if response == Gtk.ResponseType.OK: self.log("User chose a URI to save project to") # need to do this to work around bug in Gst.uri_construct # which escapes all /'s in path! - uri = "file://" + chooser.get_filename() + uri = "file://" + chooser.get_current_folder().get_uri() + '/' + chooser.get_current_name() file_filter = chooser.get_filter().get_name() self.log("uri:%s , filter:%s", uri, file_filter) - self.settings.lastProjectFolder = chooser.get_current_folder() - ret = uri + self.settings.lastProjectFolder = chooser.get_current_folder().get_uri() + self.app.project_manager.save_project(uri) else: self.log("User didn't choose a URI to save project to") - ret = None chooser.destroy() - return ret - - def __save_frame_cb(self, unused_action, unused_param): - """Exports a snapshot of the current frame as an image file.""" - res = self._show_save_screenshot_dialog() - if res: - path, mime = res[0], res[1] - self.app.project_manager.current_project.pipeline.save_thumbnail( - -1, -1, mime, path) def _show_save_screenshot_dialog(self): """Asks the user where to save the current frame. -- GitLab From 178bfc2738a45636fb6f49d7dfb8db9fdb30825f Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 1 Mar 2023 18:57:26 +0530 Subject: [PATCH 095/132] Use callback on export as archive dialog --- pitivi/editorperspective.py | 42 +++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 55c9e40ee..4770c0edd 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -457,15 +457,7 @@ class EditorPerspective(Perspective, Loggable): self.app.project_manager.revert_to_saved_project() def __export_project_cb(self, unused_action, unused_param): - uri = self._show_export_dialog(self.app.project_manager.current_project) - result = None - if uri: - result = self.app.project_manager.export_project( - self.app.project_manager.current_project, uri) - - if not result: - self.log("Project couldn't be exported") - return result + self._show_export_dialog(self.app.project_manager.current_project) def __project_settings_cb(self, unused_action, unused_param): self.show_project_settings_dialog() @@ -697,7 +689,6 @@ class EditorPerspective(Perspective, Loggable): chooser.set_default_response(Gtk.ResponseType.OK) chooser.set_select_multiple(False) - chooser.props.do_overwrite_confirmation = True asset = GES.Formatter.get_default() asset_extension = asset.get_meta(GES.META_FORMATTER_EXTENSION) @@ -714,20 +705,9 @@ class EditorPerspective(Perspective, Loggable): default.add_pattern("*") chooser.add_filter(default) - response = chooser.run() - if response == Gtk.ResponseType.OK: - self.log("User chose a URI to export project to") - # need to do this to work around bug in Gst.uri_construct - # which escapes all /'s in path! - uri = "file://" + chooser.get_filename() - self.log("uri: %s", uri) - ret = uri - else: - self.log("User didn't choose a URI to export project to") - ret = None + chooser.connect('response', self._export_dialog_response_cb) - chooser.destroy() - return ret + chooser.show() def save_project_as(self): self._show_save_as_dialog() @@ -769,6 +749,22 @@ class EditorPerspective(Perspective, Loggable): self.app.project_manager.current_project.pipeline.save_thumbnail( -1, -1, mime, path) + def _export_dialog_response_cb(self, chooser, response): + if response == Gtk.ResponseType.OK: + self.log("User chose a URI to export project to") + # need to do this to work around bug in Gst.uri_construct + # which escapes all /'s in path! + uri = "file://" + chooser.get_current_folder().get_uri() + '/' + chooser.get_current_name() + self.log("uri: %s", uri) + result = self.app.project_manager.export_project( + self.app.project_manager.current_project, uri) + if not result: + self.log("Project couldn't be exported") + else: + self.log("User didn't choose a URI to export project to") + + chooser.destroy() + def _save_as_dialog_response_cb(self, chooser, response): if response == Gtk.ResponseType.OK: self.log("User chose a URI to save project to") -- GitLab From f0f393c2874804ef66e635932e95b51dcf8a9f6d Mon Sep 17 00:00:00 2001 From: Aryan Kaushik <73686-Aryan20@users.noreply.gitlab.gnome.org> Date: Wed, 1 Mar 2023 19:39:40 +0530 Subject: [PATCH 096/132] Fix halign of favourite button in medialibrary --- pitivi/effects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/effects.py b/pitivi/effects.py index c3fb18204..09829b4a7 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -520,7 +520,7 @@ class EffectListWidget(Gtk.Box, Loggable): # Set up favourite button fav_button = Gtk.Button() fav_button.set_has_frame(False) - fav_button.props.halign = Gtk.Align.CENTER + fav_button.props.halign = Gtk.Align.END fav_button.props.valign = Gtk.Align.CENTER fav_button.set_margin_top(SPACING / 2) fav_button.set_margin_bottom(SPACING / 2) -- GitLab From 0168ac582707f8e77799a87f7f68939f2a57a458 Mon Sep 17 00:00:00 2001 From: Matthieu CHARETTE Date: Sat, 22 Apr 2023 09:01:14 +0200 Subject: [PATCH 097/132] Use paintable to load project thumbs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use try block for thumb error handling Size icon according to thumb size Add typing annotations for get_thumb --- pitivi/greeterperspective.py | 2 +- pitivi/project.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index c3c23ee23..033432b33 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -74,7 +74,7 @@ class ProjectInfoRow(Gtk.ListBoxRow): beautify_last_updated_timestamp(recent_project_item.get_modified().to_unix())) def __load_thumb_cb(self): - self.__thumb.set_pixbuf(Project.get_thumb(self.uri)) + self.__thumb.set_paintable(Project.get_thumb(self.uri)) return False diff --git a/pitivi/project.py b/pitivi/project.py index 1d12c9bb6..a7a9de4f2 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -31,6 +31,7 @@ from urllib.parse import unquote from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES +from gi.repository import Gio from gi.repository import GLib from gi.repository import GObject from gi.repository import Gst @@ -850,17 +851,17 @@ class Project(Loggable, GES.Project): return os.path.join(thumbs_cache_dir, thumb_hash) + ".png" @classmethod - def get_thumb(cls, uri): + def get_thumb(cls, uri: str) -> Gdk.Paintable: """Gets the project thumb, if exists, else the default thumb or None.""" + file = Gio.File.new_for_path(cls.get_thumb_path(uri, SCALED_THUMB_DIR)) try: - thumb = GdkPixbuf.Pixbuf.new_from_file(cls.get_thumb_path(uri, SCALED_THUMB_DIR)) + thumb = Gdk.Texture.new_from_file(file) except GLib.Error: - # Try to get the default thumb. - try: - thumb = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()).lookup_icon("video-x-generic", "", 128, 1, Gtk.TextDirection.NONE, 0) - except GLib.Error: - return None - thumb = scale_pixbuf(thumb, SCALED_THUMB_WIDTH, SCALED_THUMB_HEIGHT) + thumb = Gtk.IconTheme.get_for_display( + Gdk.Display.get_default()).lookup_icon( + "video-x-generic", "", + min(SCALED_THUMB_WIDTH, SCALED_THUMB_HEIGHT), 1, + Gtk.TextDirection.NONE, 0) return thumb -- GitLab From f4220df165ec8524af0f640a8e05676c1b29f26f Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Mon, 15 May 2023 21:30:41 +0530 Subject: [PATCH 098/132] Gtk.Layout replacement --- pitivi/timeline/elements.py | 4 ++-- pitivi/timeline/layer.py | 4 ++-- pitivi/timeline/markers.py | 2 +- pitivi/timeline/previewers.py | 20 ++++++++++---------- pitivi/timeline/timeline.py | 21 +++++++++++++-------- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index ec3125491..ed34bfc6e 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -641,7 +641,7 @@ class MultipleKeyframeCurve(KeyframeCurve): self.set_tooltip_markup(markup) -class TimelineElement(Gtk.Layout, Zoomable, Loggable): +class TimelineElement(Gtk.Fixed, Zoomable, Loggable): __gsignals__ = { # Signal the keyframes curve are being hovered "curve-enter": (GObject.SignalFlags.RUN_LAST, None, ()), @@ -650,7 +650,7 @@ class TimelineElement(Gtk.Layout, Zoomable, Loggable): } def __init__(self, element, timeline): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) Zoomable.__init__(self) Loggable.__init__(self) diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 4d9aab29d..a722b2e7c 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -298,13 +298,13 @@ class LayerControls(Gtk.Box, Loggable): self.__icon = icon -class Layer(Gtk.Layout, Loggable): +class Layer(Gtk.Fixed, Loggable): """Container for the clips widgets of a layer.""" __gtype_name__ = "PitiviLayer" def __init__(self, ges_layer, timeline): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) Loggable.__init__(self) self.ges_layer = ges_layer diff --git a/pitivi/timeline/markers.py b/pitivi/timeline/markers.py index 0f0c8b05f..0fac0150a 100644 --- a/pitivi/timeline/markers.py +++ b/pitivi/timeline/markers.py @@ -110,7 +110,7 @@ class MarkersBox(Gtk.Box, Zoomable, Loggable): Zoomable.__init__(self) Loggable.__init__(self) - self.layout = Gtk.Layout() + self.layout = Gtk.Fixed() self.append(self.layout) self.add_css_class("MarkersBox") diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py index 3b315c826..6ef7edbaf 100644 --- a/pitivi/timeline/previewers.py +++ b/pitivi/timeline/previewers.py @@ -411,7 +411,7 @@ class Previewer(GObject.Object): return max(THUMB_PERIOD, quantized) -class ImagePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): +class ImagePreviewer(Gtk.Fixed, Previewer, Zoomable, Loggable): """A previewer widget drawing the same thumbnail repeatedly. Can be used for Image clips or Color clips. @@ -421,7 +421,7 @@ class ImagePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): __gsignals__ = PREVIEW_GENERATOR_SIGNALS def __init__(self, ges_elem, max_cpu_usage): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) Previewer.__init__(self, GES.TrackType.VIDEO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) @@ -833,7 +833,7 @@ class AssetPreviewer(Previewer, Loggable): self.pipeline.set_state(Gst.State.READY) -class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable): +class VideoPreviewer(Gtk.Fixed, AssetPreviewer, Zoomable): """A video previewer widget, drawing thumbnails. Attributes: @@ -845,7 +845,7 @@ class VideoPreviewer(Gtk.Layout, AssetPreviewer, Zoomable): __gsignals__ = PREVIEW_GENERATOR_SIGNALS def __init__(self, ges_elem, max_cpu_usage): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) Zoomable.__init__(self) AssetPreviewer.__init__(self, get_proxy_target(ges_elem), max_cpu_usage) @@ -1163,13 +1163,13 @@ def get_wavefile_location_for_uri(uri): return os.path.join(cache_dir, filename) -class AudioPreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): +class AudioPreviewer(Gtk.Fixed, Previewer, Zoomable, Loggable): """Audio previewer using the results from the "level" GStreamer element.""" __gsignals__ = PREVIEW_GENERATOR_SIGNALS def __init__(self, ges_elem, max_cpu_usage): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) Previewer.__init__(self, GES.TrackType.AUDIO, max_cpu_usage) Zoomable.__init__(self) Loggable.__init__(self) @@ -1394,13 +1394,13 @@ class AudioPreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): Zoomable.__del__(self) -class TitlePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): +class TitlePreviewer(Gtk.Fixed, Previewer, Zoomable, Loggable): """Title Clip previewer using Pango to draw text on the clip.""" __gsignals__ = PREVIEW_GENERATOR_SIGNALS def __init__(self, ges_elem): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) Previewer.__init__(self, GES.TrackType.VIDEO, None) Zoomable.__init__(self) Loggable.__init__(self) @@ -1492,11 +1492,11 @@ class TitlePreviewer(Gtk.Layout, Previewer, Zoomable, Loggable): pass -class MiniPreview(Gtk.Layout): +class MiniPreview(Gtk.Fixed): """Mini Clip previewer to draw color filled mini clips.""" def __init__(self, color): - Gtk.Layout.__init__(self) + Gtk.Fixed.__init__(self) self.add_css_class("MiniPreviewer") self.color = color self.props.height_request = MINI_LAYER_HEIGHT diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 9b0fe680c..4737a734b 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -24,6 +24,7 @@ from gi.repository import Gdk from gi.repository import GES from gi.repository import Gio from gi.repository import GLib +from gi.repository import Graphene from gi.repository import Gst from gi.repository import Gtk @@ -224,7 +225,7 @@ class Marquee(Gtk.Box, Loggable): start_pos, end_pos) -class LayersLayout(Gtk.Layout, Loggable): +class LayersLayout(Gtk.ScrolledWindow, Loggable): """Layout for displaying scrollable layers, the playhead, snap indicator. The layers are actual widgets in a vertical Gtk.Box. @@ -239,9 +240,10 @@ class LayersLayout(Gtk.Layout, Loggable): """ def __init__(self, timeline): - Gtk.Layout.__init__(self) + Gtk.ScrolledWindow.__init__(self) Loggable.__init__(self) + self.fixed = Gtk.Fixed() self._timeline = timeline self.snap_position = 0 @@ -249,16 +251,19 @@ class LayersLayout(Gtk.Layout, Loggable): self.layers_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.layers_vbox.add_css_class("LayersBox") - self.put(self.layers_vbox, 0, 0) + self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER) + self.fixed.put(self.layers_vbox, 0, 0) self.marquee = Marquee(timeline, self) - self.put(self.marquee, 0, 0) + self.fixed.put(self.marquee, 0, 0) self.layers_vbox.connect("size-allocate", self.__size_allocate_cb) - def do_draw(self, cr): + def do_snapshot(self, snapshot): """Draws the children and indicators.""" - Gtk.Layout.do_draw(self, cr) + Gtk.Widget.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) + cr = snapshot.append_cairo(bounds) self._draw_playhead(cr) self._draw_snap_indicator(cr) @@ -291,9 +296,9 @@ class LayersLayout(Gtk.Layout, Loggable): def __size_allocate_cb(self, unused_widget, allocation): """Sets the size of the scrollable area to fit the layers_vbox.""" self.log("The size of the layers_vbox changed: %sx%s", allocation.width, allocation.height) - self.props.width = allocation.width # The additional space is for the 'Add layer' button. - self.props.height = allocation.height + LAYER_HEIGHT / 2 + self.set_max_content_width(allocation.width) + self.set_max_content_height(allocation.height + LAYER_HEIGHT / 2) class FullLayersLayout(LayersLayout, Zoomable): -- GitLab From 4aa708ea1a2c317dd62c008154d505bf32b512d7 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 16 May 2023 22:01:32 +0530 Subject: [PATCH 099/132] Implement Drag and Drop EventController --- pitivi/clipproperties.py | 86 +++++++++++++++++--------------- pitivi/effects.py | 27 +++++----- pitivi/greeterperspective.py | 20 ++++---- pitivi/medialibrary.py | 66 ++++++++++++------------- pitivi/timeline/elements.py | 44 +++++++---------- pitivi/timeline/timeline.py | 96 ++++++++++++++++++------------------ pitivi/utils/ui.py | 5 -- 7 files changed, 171 insertions(+), 173 deletions(-) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index cdbc3c2f8..b6465c53f 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -54,7 +54,6 @@ from pitivi.utils.misc import disconnect_all_by_func from pitivi.utils.pipeline import PipelineError from pitivi.utils.timeline import SELECT from pitivi.utils.ui import disable_scroll -from pitivi.utils.ui import EFFECT_TARGET_ENTRY from pitivi.utils.ui import get_listbox_children from pitivi.utils.ui import PADDING from pitivi.utils.ui import SPACING @@ -645,8 +644,7 @@ class EffectProperties(Gtk.Expander, Loggable): self.cover_object_button.set_direction(Gtk.ArrowType.NONE) self.object_tracker_box.prepend(self.cover_object_button) - self.drag_dest_set(Gtk.DestDefaults.DROP, [EFFECT_TARGET_ENTRY], - Gdk.DragAction.COPY) + drop_target = Gtk.DropTarget.new(GObject.TYPE_STRING, Gdk.DragAction.COPY) self.expander_box.prepend(self.effects_listbox) self.expander_box.prepend(self.add_effect_button) @@ -655,9 +653,11 @@ class EffectProperties(Gtk.Expander, Loggable): self.set_child(self.expander_box) # Connect all the widget signals - self.connect("drag-motion", self._drag_motion_cb) - self.connect("drag-leave", self._drag_leave_cb) - self.connect("drag-data-received", self._drag_data_received_cb) + drop_target.connect("accept", self._accept_cb) + drop_target.connect("motion", self._motion_cb) + drop_target.connect("leave", self._leave_cb) + drop_target.connect("drop", self._drop_cb, self) + self.add_controller(drop_target) self.add_effect_button.connect("activate", self._add_effect_button_toggled_cb) if self.cover_object_button: @@ -727,14 +727,15 @@ class EffectProperties(Gtk.Expander, Loggable): row.set_child(event_box) # Set up drag&drop - event_box.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, - [EFFECT_TARGET_ENTRY], Gdk.DragAction.MOVE) - event_box.connect("drag-begin", self._drag_begin_cb) - event_box.connect("drag-data-get", self._drag_data_get_cb) + drag_source = Gtk.DragSource.new() + drag_source.set_actions(Gdk.DragAction.MOVE) + drag_source.connect("drag-begin", self._drag_begin_cb, event_box) + drag_source.connect("prepare", self._prepare_cb, event_box) + event_box.add_controller(drag_source) - row.drag_dest_set(Gtk.DestDefaults.ALL, [EFFECT_TARGET_ENTRY], - Gdk.DragAction.MOVE | Gdk.DragAction.COPY) - row.connect("drag-data-received", self._drag_data_received_cb) + row_drop_target = Gtk.DropTarget.new(GObject.TYPE_INT, Gdk.DragAction.MOVE) + row_drop_target.connect("drop", self._drop_cb) + row.add_controller(row_drop_target) remove_effect_button.connect("clicked", self._remove_button_cb, row) toggle.connect("toggled", self._effect_active_toggle_cb, row) @@ -862,31 +863,35 @@ class EffectProperties(Gtk.Expander, Loggable): self._disconnect_from_track_element(track_element) self._remove_effect_row(track_element) - def _drag_begin_cb(self, eventbox, context): + def _drag_begin_cb(self, drag_source, drag, eventbox): """Draws the drag icon.""" row = eventbox.get_parent() alloc = row.get_allocation() - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, alloc.width, alloc.height) - ctx = cairo.Context(surface) + paintable = Gdk.Paintable.new_empty(alloc.width, alloc.height) + ctx = cairo.Context(paintable) row.draw(ctx) ctx.paint_with_alpha(0.35) - Gtk.drag_set_icon_surface(context, surface) + drag_source.set_icon(paintable, alloc.width / 2, alloc.height / 2) - def _drag_data_get_cb(self, eventbox, drag_context, selection_data, unused_info, unused_timestamp): + def _prepare_cb(self, drag_source, unused_x, unused_y, eventbox): row = eventbox.get_parent() - effect_info = self.app.effects.get_info(row.effect) - effect_name = effect_info.human_name - - data = bytes(effect_name, "UTF-8") - selection_data.set(drag_context.list_targets()[0], 0, data) - - def _drag_motion_cb(self, unused_widget, unused_drag_context, unused_x, y, unused_timestamp): - """Highlights some widgets to indicate it can receive drag&drop.""" + row_index = row.get_index() + data = GObject.Value() + data.set_int(int(row_index)) + content_provider = Gdk.ContentProvider.new_for_value(data) + drag_source.set_content(content_provider) + return content_provider + + def _accept_cb(self, drop_target, drop): self.debug( "Something is being dragged in the clip properties' effects list") + return True + + def _motion_cb(self, drop_target, x, y): + """Highlights some widgets to indicate it can receive drag&drop.""" row = self.effects_listbox.get_row_at_y(y) if row: self.effects_listbox.drag_highlight_row(row) @@ -894,7 +899,7 @@ class EffectProperties(Gtk.Expander, Loggable): else: self.effects_listbox.drag_highlight() - def _drag_leave_cb(self, unused_widget, drag_context, unused_timestamp): + def _leave_cb(self, drop_target): """Unhighlights the widgets which can receive drag&drop.""" self.debug( "The item being dragged has left the clip properties' effects list") @@ -905,21 +910,23 @@ class EffectProperties(Gtk.Expander, Loggable): def __get_time_effects(self): return [effect for effect in self.clip.get_top_effects() if is_time_effect(effect)] - def _drag_data_received_cb(self, widget, drag_context, x, y, selection_data, unused_info, timestamp): + def _drop_cb(self, drop_target, value, x, y, widget): + """Handles the drop of an effect.""" + drop = drop_target.get_drop() if not self.clip: # Indicate that a drop will not be accepted. - Gdk.drag_status(drag_context, 0, timestamp) - return + drop_target.reject() + return False if self.effects_listbox.get_row_at_y(y): - # Drop happened inside the lisbox + # Drop happened inside the listbox drop_index = widget.get_index() else: - drop_index = len(get_listbox_children(self.effects_listbox)) - 1 + drop_index = len(self.effects_listbox.get_children()) - if drag_context.get_suggested_action() == Gdk.DragAction.COPY: + if drop_target.get_action() == Gdk.DragAction.COPY: # An effect dragged probably from the effects list. - factory_name = str(selection_data.get_data(), "UTF-8") + factory_name = value top_effect_index = drop_index + len(self.__get_time_effects()) self.debug("Effect dragged at position %s - computed top effect index %s", @@ -934,15 +941,14 @@ class EffectProperties(Gtk.Expander, Loggable): if effect: self.clip.set_top_effect_index(effect, top_effect_index) - elif drag_context.get_suggested_action() == Gdk.DragAction.MOVE: + elif drop_target.get_action() == Gdk.DragAction.MOVE: # An effect dragged from the same listbox to change its position. - source_eventbox = Gtk.drag_get_source_widget(drag_context) - source_row = source_eventbox.get_parent() - source_index = source_row.get_index() - + # Source index is passed as data + source_index = value self._move_effect(self.clip, source_index, drop_index) - drag_context.finish(True, False, timestamp) + drop.finish(drop.get_action()) + return True def _move_effect(self, clip, source_index, drop_index): # Handle edge cases diff --git a/pitivi/effects.py b/pitivi/effects.py index 09829b4a7..13533d825 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -51,7 +51,6 @@ from pitivi.trackerperspective import EFFECT_TRACKED_OBJECT_ID_META from pitivi.trackerperspective import EFFECT_TRACKED_OBJECT_NAME_META from pitivi.utils.loggable import Loggable from pitivi.utils.ui import disable_scroll -from pitivi.utils.ui import EFFECT_TARGET_ENTRY from pitivi.utils.ui import get_listbox_children from pitivi.utils.ui import get_widget_children from pitivi.utils.ui import PADDING @@ -535,9 +534,10 @@ class EffectListWidget(Gtk.Box, Loggable): # Set up drag behavoir eventbox = Gtk.Box() - eventbox.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) - eventbox.connect("drag-data-get", self._drag_data_get_cb) - eventbox.connect("drag-begin", self._drag_begin_cb) + eventbox_controller = Gtk.DragSource.new() + eventbox_controller.connect("drag-begin", self._drag_begin_cb) + eventbox_controller.connect("prepare", self._prepare_cb, eventbox) + eventbox.add_controller(eventbox_controller) eventbox.append(effect_box) row = Gtk.ListBoxRow(selectable=False) @@ -545,27 +545,28 @@ class EffectListWidget(Gtk.Box, Loggable): return row - def _drag_data_get_cb(self, eventbox, drag_context, selection_data, unused_info, unused_timestamp): + def _prepare_cb(self, drag_source, start_x, start_y, eventbox): effect_box = eventbox.get_child() - data = bytes(effect_box.effect_name, "UTF-8") - selection_data.set(drag_context.list_targets()[0], 0, data) + data = GObject.Value(GObject.TYPE_STRING) + data.set_value(str(effect_box.effect_name)) + content_provider = Gdk.ContentProvider.new_for_value(data) + drag_source.set_content(content_provider) + return content_provider - def _drag_begin_cb(self, eventbox, context): - # Draw drag-icon + def _drag_begin_cb(self, drag_source, drag): icon = self._drag_icon icon_height = icon.get_height() icon_width = icon.get_width() - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, icon_width, icon_height) - ctx = cairo.Context(surface) + paintable = Gdk.Paintable.new_empty(icon_width, icon_height) + ctx = cairo.Context(paintable) # Center the icon around the cursor. ctx.translate(icon_width / 2, icon_height / 2) - surface.set_device_offset(-icon_width / 2, -icon_height / 2) Gdk.cairo_set_source_pixbuf(ctx, icon, 0, 0) ctx.paint_with_alpha(0.35) - Gtk.drag_set_icon_surface(context, surface) + drag_source.set_icon(paintable, icon_width / 2, icon_height / 2) def effects_listbox_row_activated_cb(self, listbox, row): """Handles the activation of a row representing an effect.""" diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 033432b33..86ea29961 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -37,7 +37,6 @@ from pitivi.utils.ui import get_listbox_children from pitivi.utils.ui import GREETER_PERSPECTIVE_CSS from pitivi.utils.ui import PADDING from pitivi.utils.ui import SPACING -from pitivi.utils.ui import URI_TARGET_ENTRY MAX_RECENT_PROJECTS = 10 @@ -130,9 +129,10 @@ class GreeterPerspective(Perspective): logo.set_pixel_size(256) self.toplevel_widget = builder.get_object("toplevel_vbox") - self.toplevel_widget.drag_dest_set( - Gtk.DestDefaults.ALL, [URI_TARGET_ENTRY], Gdk.DragAction.COPY) - self.toplevel_widget.connect("drag-data-received", self.__drag_data_received_cb) + + drop_target = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) + drop_target.connect("drop", self._drop_cb) + self.toplevel_widget.add_controller(drop_target) self.__topvbox = builder.get_object("topvbox") self.__welcome_vbox = builder.get_object("welcome_vbox") @@ -322,18 +322,20 @@ class GreeterPerspective(Perspective): assert not visible_options return menu_button - def __drag_data_received_cb(self, unused_widget, unused_context, unused_x, - unused_y, data, unused_info, unused_time): + def _drop_cb(self, drop_target, value, x, y): """Opens the project file dragged from Nautilus.""" - uris = data.get_uris() - if not uris: - return + files = value.get_files() + if not files: + return False + uris = [file.get_uri() for file in files] uri = uris[0] extension = os.path.splitext(uri)[1][1:] if extension in self.__project_filter: self.app.project_manager.load_project(uri) + return True + def __new_project_cb(self, unused_action, unused_param): self.app.project_manager.new_blank_project() diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index caaeddde7..3d48639fc 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -56,13 +56,11 @@ from pitivi.utils.proxy import get_proxy_target from pitivi.utils.proxy import ProxyingStrategy from pitivi.utils.ui import beautify_asset from pitivi.utils.ui import beautify_eta -from pitivi.utils.ui import FILE_TARGET_ENTRY from pitivi.utils.ui import info_name from pitivi.utils.ui import LARGE_THUMB_WIDTH from pitivi.utils.ui import PADDING from pitivi.utils.ui import SMALL_THUMB_WIDTH from pitivi.utils.ui import SPACING -from pitivi.utils.ui import URI_TARGET_ENTRY # ToDo: Fix Import Dialog PreviewWidget and filter # from pitivi.mediafilespreviewer import PreviewWidget # from pitivi.utils.ui import filter_unsupported_media_files @@ -614,11 +612,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable): project_manager.connect("project-closed", self._project_closed_cb) # Drag and Drop - self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, - [URI_TARGET_ENTRY, FILE_TARGET_ENTRY], - Gdk.DragAction.COPY) - self.drag_dest_add_uri_targets() - self.connect("drag_data_received", self._drag_data_received_cb) + drop_target = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) + drop_target.connect("enter", self._enter_cb) + drop_target.connect("drop", self._drop_cb) + self.add_controller(drop_target) self._setup_view_as_drag_and_drop_source() @@ -726,12 +723,11 @@ class MediaLibraryWidget(Gtk.Box, Loggable): return 1 def _setup_view_as_drag_and_drop_source(self): - self.flowbox.drag_source_set( - Gdk.ModifierType.BUTTON1_MASK, [URI_TARGET_ENTRY], Gdk.DragAction.COPY) - self.flowbox.drag_source_add_uri_targets() - self.flowbox.connect("drag-data-get", self._flowbox_drag_data_get_cb) - self.flowbox.connect_after("drag-begin", self._flowbox_drag_begin_cb) - self.flowbox.connect("drag-end", self._flowbox_drag_end_cb) + flowbox_controller = Gtk.DragSource.new() + flowbox_controller.connect("drag-begin", self._flowbox_drag_begin_cb) + flowbox_controller.connect("prepare", self._flowbox_prepare_cb) + flowbox_controller.connect("drag-end", self._flowbox_drag_end_cb) + self.flowbox.add_controller(flowbox_controller) def _store_items_changed_cb(self, store_model, unused_position, unused_removed, unused_added): if store_model.get_n_items() == 0: @@ -1679,26 +1675,31 @@ class MediaLibraryWidget(Gtk.Box, Loggable): else: self._project.add_uris(uris) - def _drag_data_received_cb(self, widget, context, x, y, - selection, targettype, time_): - """Handles data being dragged onto self.""" - self.debug("targettype: %d, selection.data: %r", - targettype, selection.get_data()) - uris = selection.get_uris() - # Scan in the background what was dragged and - # import whatever can be imported. - self.app.threads.add_thread(PathWalker, uris, self.__paths_walked_cb) - - def _flowbox_drag_data_get_cb(self, view, context, data, info, timestamp): - uris = [self.store[path].uri for path in self._dragged_paths] - data.set_uris(uris) + def _enter_cb(self, drop_target, x, y): + return drop_target.get_actions() - def _flowbox_drag_begin_cb(self, view, context): + def _drop_cb(self, drop_target, value, x, y): + files = value.get_files() + uris = [file.get_uri() for file in files] + self.app.threads.add_thread(PathWalker, uris, self.__paths_walked_cb) + return True + + def _flowbox_prepare_cb(self, drag_source, unused_x, unused_y): + uris = [Gio.File.new_for_uri(self.store[path].uri) for path in self._dragged_paths] + file_list = Gdk.FileList.new_from_list(uris) + value = GLib.Value() + value.init(Gdk.FileList) + value.set_value(file_list) + content_provider = Gdk.ContentProvider.new_for_value(value) + drag_source.set_content(content_provider) + return content_provider + + def _flowbox_drag_begin_cb(self, drag_source, drag): self.dragged = True self._dragged_paths = self.get_selected_paths() if not self._dragged_paths: - context.drag_abort(int(time.time())) + drag_source.drag_cancel() else: row = self.store[self._dragged_paths[0]] icon = row.icon_128 @@ -1706,18 +1707,17 @@ class MediaLibraryWidget(Gtk.Box, Loggable): icon_height = icon.get_height() icon_width = icon.get_width() - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, icon_width, icon_height) - ctx = cairo.Context(surface) + paintable = Gdk.Paintable.new_empty(icon_width, icon_height) + ctx = cairo.Context(paintable) # Center the icon around the cursor. ctx.translate(icon_width / 2, icon_height / 2) - surface.set_device_offset(-icon_width / 2, -icon_height / 2) Gdk.cairo_set_source_pixbuf(ctx, icon, 0, 0) ctx.paint_with_alpha(0.35) - Gtk.drag_set_icon_surface(context, surface) + drag_source.set_icon(paintable, icon_width, icon_height) - def _flowbox_drag_end_cb(self, view, context): + def _flowbox_drag_end_cb(self, drag_source, drag, delete_data): self.info("Drag operation ended") self.dragged = False diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index ed34bfc6e..08fa6dfbb 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -56,7 +56,6 @@ from pitivi.utils.timeline import UNSELECT from pitivi.utils.timeline import Zoomable from pitivi.utils.ui import CURSORS from pitivi.utils.ui import DRAG_CURSOR -from pitivi.utils.ui import EFFECT_TARGET_ENTRY from pitivi.utils.ui import get_widget_children from pitivi.utils.ui import NORMAL_CURSOR from pitivi.utils.ui import set_state_flags_recurse @@ -1226,32 +1225,27 @@ class Clip(Gtk.Box, Loggable): self.ges_clip.connect_after("child-removed", self._child_removed_cb) # To be able to receive effects dragged on clips. - self.drag_dest_set(0, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) - self.connect("drag-drop", self.__drag_drop_cb) + drag_controller = Gtk.DropTarget.new(GObject.TYPE_STRING, Gdk.DragAction.COPY) + drag_controller.connect("drop", self.__drop_cb) + self.add_controller(drag_controller) - def __drag_drop_cb(self, widget, context, x, y, timestamp): + def __drop_cb(self, drop_target, unused_value, unused_x, unused_y): success = False - - target = self.drag_dest_find_target(context, None) - if not target: - return False - - if target.name() == EFFECT_TARGET_ENTRY.target: - self.info("Adding effect %s", self.timeline.drop_data) - self.timeline.selection.set_selection([self.ges_clip], SELECT) - self.app.gui.editor.switch_context_tab(self.ges_clip) - - effect_info = self.app.effects.get_info(self.timeline.drop_data) - pipeline = self.timeline.ges_timeline.get_parent() - with self.app.action_log.started("add effect", - finalizing_action=CommitTimelineFinalizingAction(pipeline), - toplevel=True): - self.add_effect(effect_info) - self.timeline.clean_drop_data() - success = True - - Gtk.drag_finish(context, success, False, timestamp) - + drop = drop_target.get_drop() + self.info("Adding effect %s", self.timeline.drop_data) + self.timeline.selection.set_selection([self.ges_clip], SELECT) + self.app.gui.editor.switch_context_tab(self.ges_clip) + + effect_info = self.app.effects.get_info(self.timeline.drop_data) + pipeline = self.timeline.ges_timeline.get_parent() + with self.app.action_log.started("add effect", + finalizing_action=CommitTimelineFinalizingAction(pipeline), + toplevel=True): + self.add_effect(effect_info) + self.timeline.clean_drop_data() + success = True + + drop.finish(drop.get_actions()) return success def add_effect(self, effect_info): diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 4737a734b..de8169af6 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -24,6 +24,7 @@ from gi.repository import Gdk from gi.repository import GES from gi.repository import Gio from gi.repository import GLib +from gi.repository import GObject from gi.repository import Graphene from gi.repository import Gst from gi.repository import Gtk @@ -56,7 +57,6 @@ from pitivi.utils.timeline import Selection from pitivi.utils.timeline import TimelineError from pitivi.utils.timeline import UNSELECT from pitivi.utils.timeline import Zoomable -from pitivi.utils.ui import EFFECT_TARGET_ENTRY from pitivi.utils.ui import LAYER_HEIGHT from pitivi.utils.ui import MINI_LAYER_HEIGHT from pitivi.utils.ui import PLAYHEAD_COLOR @@ -68,7 +68,6 @@ from pitivi.utils.ui import SNAPBAR_COLOR from pitivi.utils.ui import SNAPBAR_WIDTH from pitivi.utils.ui import SPACING from pitivi.utils.ui import TOUCH_INPUT_SOURCES -from pitivi.utils.ui import URI_TARGET_ENTRY from pitivi.utils.widgets import ZoomBox @@ -510,22 +509,25 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.__last_clips_on_leave = None # To be able to receive effects dragged on clips. - self.drag_dest_set(0, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) - self.mini_layout_container.drag_dest_set(0, [EFFECT_TARGET_ENTRY], Gdk.DragAction.COPY) - # To be able to receive assets dragged from the media library. - self.drag_dest_add_uri_targets() - self.mini_layout_container.drag_dest_add_uri_targets() - - self.connect("drag-motion", self._drag_motion_cb) - self.connect("drag-leave", self._drag_leave_cb) - self.connect("drag-drop", self._drag_drop_cb) - self.connect("drag-data-received", self._drag_data_received_cb) + drop_target = Gtk.DropTarget.new(GObject.TYPE_INVALID, Gdk.DragAction.COPY) + drop_target.set_gtypes([GObject.TYPE_STRING, Gdk.FileList]) + mini_layout_controller = Gtk.DropTarget.new(GObject.TYPE_INVALID, Gdk.DragAction.COPY) + mini_layout_controller.set_gtypes([GObject.TYPE_STRING, Gdk.FileList]) + + drop_target.connect("accept", self._accept_cb) + drop_target.connect("notify", self._notify_cb) + drop_target.connect("motion", self._motion_cb, self) + drop_target.connect("leave", self._leave_cb) + drop_target.connect("drop", self._drop_cb) + self.add_controller(drop_target) mini = True - self.mini_layout_container.connect("drag-motion", self._drag_motion_cb, mini) - self.mini_layout_container.connect("drag-leave", self._drag_leave_cb) - self.mini_layout_container.connect("drag-drop", self._drag_drop_cb) - self.mini_layout_container.connect("drag-data-received", self._drag_data_received_cb) + mini_layout_controller.connect("accept", self._accept_cb) + mini_layout_controller.connect("notify", self._notify_cb) + mini_layout_controller.connect("motion", self._motion_cb, self.mini_layout_container, mini) + mini_layout_controller.connect("leave", self._leave_cb) + mini_layout_controller.connect("drop", self._drop_cb) + self.mini_layout_container.add_controller(mini_layout_controller) self.app.settings.connect("edgeSnapDeadbandChanged", self.__snap_distance_changed_cb) @@ -1166,32 +1168,44 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.dragging_group = self.selection.group() - def _drag_motion_cb(self, widget, context, x, y, timestamp, mini=False): - target = self.drag_dest_find_target(context, None) - if not target: - Gdk.drag_status(context, 0, timestamp) - return True + def _accept_cb(self, drop_target, drop): + drop_target.set_preload(True) + return True + def _notify_cb(self, drop_target, pspec): + data = drop_target.get_value() + data_type = data.get_gtype() if not self.drop_data_ready: - # We don't know yet the details of what's being dragged. - # Ask for the details. - self.drag_get_data(context, target, timestamp) - elif target.name() == URI_TARGET_ENTRY.target: + self.__last_clips_on_leave = None + if data_type == GObject.TYPE_STRING: + # Dragging an effect from the Effect Library. + factory_name = data.get_string() + self.drop_data = factory_name + self.drop_data_ready = True + elif data_type == Gdk.FileList: + self.drop_data = [file.get_uri() for file in data.get_files()] + self.drop_data_ready = True + + def _motion_cb(self, drop_target, x, y, widget, mini=False): + drop = drop_target.get_drop() + data_type = drop_target.get_value().get_gtype() + if self.drop_data_ready and data_type == Gdk.FileList: layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox x, y = widget.translate_coordinates(layers_box, x, y) if not self.dropping_clips: # The preview clips have not been created yet. self.__create_clips(x, y, mini) self.__drag_update(x, y, mini) - Gdk.drag_status(context, Gdk.DragAction.COPY, timestamp) - return True - def _drag_leave_cb(self, unused_widget, context, unused_timestamp): + drop.status(drop.get_actions(), Gdk.DragAction.COPY) + return drop_target.get_actions() + + def _leave_cb(self, drop_target): # De-highlight the separators. We still need to remember them. # See how __on_separators is used in __dragDropCb for details self._set_separators_prelight(False) - target = self.drag_dest_find_target(context, None) + data_type = drop_target.get_value().get_gtype() if self.dragging_element: self.__last_clips_on_leave = [(clip.get_layer(), clip) for clip in self.dragging_group.get_children(False)] @@ -1208,7 +1222,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.dropping_clips = False self.dragging_group.ungroup(recursive=False) self.dragging_group = None - elif target == URI_TARGET_ENTRY.target: + elif data_type == Gdk.FileList: self.clean_drop_data() def clean_drop_data(self): @@ -1216,15 +1230,15 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.drop_data = None self.dropping_clips = False - def _drag_drop_cb(self, unused_widget, context, x, y, timestamp): + def _drop_cb(self, drop_target, value, x, y): # Same as in insertEnd: this value changes during insertion, snapshot # it zoom_was_fitted = self.zoomed_fitted - target = self.drag_dest_find_target(context, None).name() + data_type = value.get_gtype() success = True self.clean_drop_data() - if target == URI_TARGET_ENTRY.target: + if data_type == Gdk.FileList: if self.__last_clips_on_leave: pipeline = self._project.pipeline with self.app.action_log.started("add clip", @@ -1248,23 +1262,9 @@ class Timeline(Gtk.Box, Zoomable, Loggable): else: success = False - Gtk.drag_finish(context, success, False, timestamp) + drop_target.get_drop().finish(drop_target.get_actions()) return success - def _drag_data_received_cb(self, unused_widget, unused_context, unused_x, - unused_y, selection_data, unused_info, timestamp): - data_type = selection_data.get_data_type().name() - if not self.drop_data_ready: - self.__last_clips_on_leave = None - if data_type == URI_TARGET_ENTRY.target: - self.drop_data = selection_data.get_uris() - self.drop_data_ready = True - elif data_type == EFFECT_TARGET_ENTRY.target: - # Dragging an effect from the Effect Library. - factory_name = str(selection_data.get_data(), "UTF-8") - self.drop_data = factory_name - self.drop_data_ready = True - # Handle layers def _layer_added_cb(self, unused_ges_timeline, ges_layer): self._add_layer(ges_layer) diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index 5f54637d0..bad615b71 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -67,11 +67,6 @@ SMALL_THUMB_WIDTH = 64 # 128 is the normal size for thumbnails, but for *icons* it looks insane. LARGE_THUMB_WIDTH = 96 -# Drag and drop -FILE_TARGET_ENTRY = Gtk.TargetEntry.new("text/plain", 0, 0) -URI_TARGET_ENTRY = Gtk.TargetEntry.new("text/uri-list", 0, 0) -EFFECT_TARGET_ENTRY = Gtk.TargetEntry.new("pitivi/effect", 0, 0) - TOUCH_INPUT_SOURCES = (Gdk.InputSource.TOUCHPAD, Gdk.InputSource.TRACKPOINT, Gdk.InputSource.TABLET_PAD) -- GitLab From b8cfde959dbbacfee7b7f6ab03ecf645ddcb2f50 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Fri, 2 Jun 2023 11:52:16 +0530 Subject: [PATCH 100/132] Drop use of dialog.run() --- pitivi/dialogs/missingasset.py | 7 +++-- pitivi/editorperspective.py | 48 ++++++++++++++++++++++++---------- pitivi/mainwindow.py | 3 ++- pitivi/project.py | 13 +++++++-- 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/pitivi/dialogs/missingasset.py b/pitivi/dialogs/missingasset.py index a0df7e97e..0ff0f92fd 100644 --- a/pitivi/dialogs/missingasset.py +++ b/pitivi/dialogs/missingasset.py @@ -127,7 +127,10 @@ class MissingAssetDialog(Gtk.Dialog, Loggable): def get_new_uri(self): """Returns new URI of the missing asset, if provided by the user.""" - response = self.run() + self.connect("response", self._response_cb) + self.show() + return self._chooser.get_uri() + + def _response_cb(self, unused_dialog, response): if response == Gtk.ResponseType.OK: self.log("User chose a new URI for the missing file") - return self._chooser.get_uri() diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 4770c0edd..10b251aad 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -571,22 +571,25 @@ class EditorPerspective(Perspective, Loggable): dialog.props.secondary_text = message - response = dialog.run() - dialog.destroy() + res = [None] + dialog.set_modal(True) + dialog.connect("response", self._project_manager_closing_project_cb_response_cb, project, project_manager, res) + dialog.show() + + return res[0] + def _project_manager_closing_project_cb_response_cb(self, dialog, response, project, project_manager, res): if response == Gtk.ResponseType.YES: if project.uri is not None and project_manager.disable_save is False: - res = self.app.project_manager.save_project() + res[0] = self.app.project_manager.save_project() else: # FixMe: Remains from switching to a callback model for save as dialog # res = self.save_project_as() - res = True + res[0] = True elif response == Gtk.ResponseType.REJECT: - res = True + res[0] = True else: - res = False - - return res + res[0] = False def _project_manager_project_closed_cb(self, project_manager, project): """Starts disconnecting the UI from the specified project. @@ -624,12 +627,22 @@ class EditorPerspective(Perspective, Loggable): _("This will reload the current project. All unsaved changes will be lost.")) dialog.set_default_response(Gtk.ResponseType.NO) dialog.set_transient_for(self.app.gui) - response = dialog.run() - dialog.destroy() - if response != Gtk.ResponseType.YES: - return False + + project_manager_response = [True] + dialog.set_modal(True) + dialog.connect("response", self._project_manager_reverting_to_saved_cb_response_cb, project_manager_response) + dialog.show() + + return project_manager_response[0] + return True + def _project_manager_reverting_to_saved_cb_response_cb(self, dialog, response, project_manager_response): + if response == Gtk.ResponseType.YES: + project_manager_response[0] = True + else: + project_manager_response[0] = False + def _project_manager_missing_uri_cb(self, project_manager, project, unused_error, asset): if project.at_least_one_asset_missing: # One asset is already missing so no point in spamming the user @@ -801,7 +814,15 @@ class EditorPerspective(Perspective, Loggable): filt.set_name(image_format) filt.add_mime_type(formats.get(image_format)[0]) chooser.add_filter(filt) - response = chooser.run() + + ret = [] + chooser.set_modal(True) + chooser.connect('response', self._save_screenshot_dialog_response_cb, formats, ret) + chooser.show() + + return ret + + def _save_screenshot_dialog_response_cb(self, chooser, response, formats, ret): if response == Gtk.ResponseType.OK: chosen_format = formats.get(chooser.get_filter().get_name()) chosen_ext = chosen_format[1][0] @@ -812,7 +833,6 @@ class EditorPerspective(Perspective, Loggable): else: ret = None chooser.destroy() - return ret def update_title(self): project = self.app.project_manager.current_project diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 8216cfdeb..dd8ecf6fc 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -225,7 +225,8 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): def __preferences_cb(self, unused_action, unused_param): dialog = PreferencesDialog(self.app) - dialog.run() + dialog.set_modal(True) + dialog.show() def __configure_cb(self, unused_widget, unused_event): """Saves the main window size.""" diff --git a/pitivi/project.py b/pitivi/project.py index a7a9de4f2..f813c2ca9 100644 --- a/pitivi/project.py +++ b/pitivi/project.py @@ -345,9 +345,18 @@ class ProjectManager(GObject.Object, Loggable): content_area.prepend(hbox) content_area.set_spacing(SPACING * 2) - response = dialog.run() + do_restore = [True] + dialog.connect("response", self._restore_from_backup_dialog_cb, do_restore) + dialog.show() + + return do_restore[0] + + def _restore_from_backup_dialog_cb(self, dialog, response_id, do_restore): dialog.destroy() - return response == Gtk.ResponseType.YES + if response_id == Gtk.ResponseType.YES: + do_restore[0] = True + else: + do_restore[0] = False def save_project(self, uri=None, formatter_type=None, backup=False): """Saves the current project. -- GitLab From 04056f18ab05b57418adefd3145e8173e016b3ae Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sat, 3 Jun 2023 10:33:33 +0530 Subject: [PATCH 101/132] Adapt to drawing model changes --- pitivi/clip_properties/alignment.py | 7 ++++++- pitivi/timeline/elements.py | 16 ++++++++++++---- pitivi/timeline/layer.py | 10 +++++++--- pitivi/timeline/previewers.py | 18 +++++++++++++++--- pitivi/timeline/ruler.py | 4 ++-- pitivi/timeline/timeline.py | 2 +- pitivi/viewer/guidelines.py | 5 ++--- pitivi/viewer/move_scale_overlay.py | 3 ++- pitivi/viewer/peak_meter.py | 8 ++++---- pitivi/viewer/safe_areas_overlay.py | 6 +++--- pitivi/viewer/title_overlay.py | 3 ++- 11 files changed, 56 insertions(+), 26 deletions(-) diff --git a/pitivi/clip_properties/alignment.py b/pitivi/clip_properties/alignment.py index f6f88c405..334b83407 100644 --- a/pitivi/clip_properties/alignment.py +++ b/pitivi/clip_properties/alignment.py @@ -18,6 +18,7 @@ # License along with this program; if not, see . from gi.repository import Gdk from gi.repository import GObject +from gi.repository import Graphene from gi.repository import Gtk from pitivi.utils.loggable import Loggable @@ -110,9 +111,13 @@ class AlignmentEditor(Gtk.Box, Loggable): height = box_height * 4 + 3 return width, height, box_width, box_height - def do_draw(self, cr): + def do_snapshot(self, snapshot): width, height, box_width, box_height = self.get_used_size() + Gtk.Widget.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, width, height) + cr = snapshot.append_cairo(bounds) + self._draw_frame(cr, width, height) # Highlight the box that the cursor is hovering over diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 08fa6dfbb..5fb5d9437 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -24,6 +24,7 @@ from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import GObject +from gi.repository import Graphene from gi.repository import Gst from gi.repository import GstController from gi.repository import Gtk @@ -803,7 +804,11 @@ class TimelineElement(Gtk.Fixed, Zoomable, Loggable): if binding.props.name == self.__controlled_property.name: self.__ensure_keyframes(binding) - def do_draw(self, cr): + def do_snapshot(self, snapshot): + Gtk.Fixed.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.__width, self.__height) + cr = snapshot.append_cairo(bounds) + self.propagate_draw(self.__background, cr) if self.previewer: @@ -1152,10 +1157,13 @@ class TrimHandle(Gtk.Box, Loggable): else: self.props.halign = Gtk.Align.START - def do_draw(self, cr): - Gtk.Box.do_draw(self, cr) + def do_snapshot(self, snapshot): + Gtk.Box.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) + cr = snapshot.append_cairo(bounds) + if TrimHandle.PIXBUF is None: - TrimHandle.PIXBUF = GdkPixbuf.Pixbuf.new_from_file( + TrimHandle.PIXBUF = GdkPixbuf.PixBuf.new_from_file( os.path.join(get_pixmap_dir(), "trimbar-focused.png")) Gdk.cairo_set_source_pixbuf(cr, TrimHandle.PIXBUF, 10, 10) diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index a722b2e7c..0c5bc87aa 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -20,6 +20,7 @@ from gettext import gettext as _ from gi.repository import Gdk from gi.repository import GES from gi.repository import Gio +from gi.repository import Graphene from gi.repository import Gtk from pitivi.timeline import elements @@ -406,7 +407,10 @@ class Layer(Gtk.Fixed, Loggable): def update_position(self): pass - def do_draw(self, cr): + def do_snapshot(self, snapshot): + Gtk.Fixed.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) + cr = snapshot.append_cairo(bounds) if self._changed: self._children.sort(key=lambda clip: clip.z_order) for child in self._children: @@ -522,8 +526,8 @@ class MiniLayer(Layer): def update_position(self): pass - def do_draw(self, context): - Layer.do_draw(self, context) + def do_snapshot(self, snapshot): + Layer.do_snapshot(self, snapshot) for layer in self.timeline.ges_timeline.get_layers(): # pylint: disable=W0212 diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py index 6ef7edbaf..bd0edd1db 100644 --- a/pitivi/timeline/previewers.py +++ b/pitivi/timeline/previewers.py @@ -29,6 +29,7 @@ from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import GLib from gi.repository import GObject +from gi.repository import Graphene from gi.repository import Gst from gi.repository import Gtk from gi.repository import Pango @@ -1295,7 +1296,11 @@ class AudioPreviewer(Gtk.Fixed, Previewer, Zoomable, Loggable): return True return False - def do_draw(self, context): + def do_snapshot(self, snapshot): + Gtk.Fixed.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) + context = snapshot.append_cairo(bounds) + if not self.samples or not self.ges_elem.get_track() or not self.ges_elem.props.active: # Nothing to draw. return @@ -1419,7 +1424,10 @@ class TitlePreviewer(Gtk.Fixed, Previewer, Zoomable, Loggable): if pspec.name == "text": self.queue_draw() - def do_draw(self, context): + def do_snapshot(self, snapshot): + Gtk.Fixed.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) + context = snapshot.append_cairo(bounds) width = self.get_allocated_width() height = self.get_allocated_height() @@ -1501,7 +1509,11 @@ class MiniPreview(Gtk.Fixed): self.color = color self.props.height_request = MINI_LAYER_HEIGHT - def do_draw(self, context): + def do_snapshot(self, snapshot): + Gtk.Fixed.do_snapshot(self, snapshot) + bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) + context = snapshot.append_cairo(bounds) + rect = Gdk.cairo_get_clip_rectangle(context)[1] context.set_source_rgb(*self.color) context.rectangle(0, 0, rect.width, rect.height) diff --git a/pitivi/timeline/ruler.py b/pitivi/timeline/ruler.py index c10aac831..2e187fef1 100644 --- a/pitivi/timeline/ruler.py +++ b/pitivi/timeline/ruler.py @@ -122,7 +122,7 @@ class ScaleRuler(Gtk.DrawingArea, Loggable): Gtk.Settings.get_default().connect("notify::gtk-theme-name", self._update_colors_cb) Gtk.Settings.get_default().connect("notify::gtk-application-prefer-dark-theme", self._update_colors_cb) - self.set_draw_func(self.do_draw) + self.set_draw_func(self.draw_func) def set_pipeline(self, pipeline): self._pipeline = pipeline @@ -173,7 +173,7 @@ class ScaleRuler(Gtk.DrawingArea, Loggable): self._set_colors() return False - def do_draw(self, unused_widget, context, width, height): + def draw_func(self, unused_widget, context, unused_width, unused_height): if self.pixbuf is None: self.info("No buffer to paint") return False diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index de8169af6..6d195183e 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -228,7 +228,7 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): """Layout for displaying scrollable layers, the playhead, snap indicator. The layers are actual widgets in a vertical Gtk.Box. - The playhead and the snap indicator are drawn on top in do_draw(). + The playhead and the snap indicator are drawn on top in do_snapshot(). Args: timeline (Timeline): The timeline indirectly containing the layout. diff --git a/pitivi/viewer/guidelines.py b/pitivi/viewer/guidelines.py index 85cd9571f..eaf48f950 100644 --- a/pitivi/viewer/guidelines.py +++ b/pitivi/viewer/guidelines.py @@ -153,6 +153,7 @@ class GuidelinesOverlay(Gtk.DrawingArea): self.active_guidelines = set() self.hide() + self.set_draw_func(self.draw_func) def add_guideline(self, guideline): if guideline not in self.active_guidelines: @@ -168,9 +169,7 @@ class GuidelinesOverlay(Gtk.DrawingArea): self.set_visible(False) self.queue_draw() - def do_draw(self, cr): - width = self.get_allocated_width() - height = self.get_allocated_height() + def draw_func(self, unused_drawing_area, cr, width, height): # Draw black border. cr.set_source_rgb(0, 0, 0) diff --git a/pitivi/viewer/move_scale_overlay.py b/pitivi/viewer/move_scale_overlay.py index ebbce6986..a9bbf2107 100644 --- a/pitivi/viewer/move_scale_overlay.py +++ b/pitivi/viewer/move_scale_overlay.py @@ -320,6 +320,7 @@ class MoveScaleOverlay(Overlay): self._source.connect("deep-notify", self.__source_property_changed_cb) self.update_from_source() + self.set_draw_func(self.draw_func) def __get_source_property(self, prop): if self.__source_property_keyframed(prop): @@ -550,7 +551,7 @@ class MoveScaleOverlay(Overlay): self.__reset_handle_sizes() self.queue_draw() - def do_draw(self, cr): + def draw_func(self, unused_drawing_area, cr, unused_width, unused_height): selected = self._is_selected() hovered = self._is_hovered() if not selected and not hovered: diff --git a/pitivi/viewer/peak_meter.py b/pitivi/viewer/peak_meter.py index 639e0ad84..9c526534d 100644 --- a/pitivi/viewer/peak_meter.py +++ b/pitivi/viewer/peak_meter.py @@ -75,11 +75,11 @@ class PeakMeter(PeakMeterWidget): self.add_css_class("frame") - self.set_draw_func(self.do_draw) + self.set_draw_func(self.draw_func) self.connect("resize", self.__resize_cb) - def do_draw(self, widget, context, width, height): + def draw_func(self, unused_widget, context, width, height): if self.pixel_buffer is None: return @@ -152,9 +152,9 @@ class PeakMeterScale(PeakMeterWidget): PeakMeterWidget.__init__(self) width = FONT_SIZE * 2 self.set_property("width_request", width) - self.set_draw_func(self.do_draw) + self.set_draw_func(self.draw_func) - def do_draw(self, widget, context, width, height): + def draw_func(self, unused_widget, context, width, height): if self.pixel_buffer is None: return diff --git a/pitivi/viewer/safe_areas_overlay.py b/pitivi/viewer/safe_areas_overlay.py index 8b77193b9..c6238fa53 100644 --- a/pitivi/viewer/safe_areas_overlay.py +++ b/pitivi/viewer/safe_areas_overlay.py @@ -29,6 +29,8 @@ class SafeAreasOverlay(Gtk.DrawingArea): self.__project.connect("safe-area-size-changed", self.__safe_areas_size_changed_cb) + self.set_draw_func(self.draw_func) + def __safe_areas_size_changed_cb(self, project): self.queue_draw() @@ -40,9 +42,7 @@ class SafeAreasOverlay(Gtk.DrawingArea): y = (widget_height - h) / 2 return round05(x), round05(y), int(w), int(h) - def do_draw(self, cr): - width = self.get_allocated_width() - height = self.get_allocated_height() + def draw_func(self, unused_drawing_area, cr, width, height): title_rect = self._compute_rect(width, height, self.__project.title_safe_area_horizontal, self.__project.title_safe_area_vertical) action_rect = self._compute_rect(width, height, self.__project.action_safe_area_horizontal, self.__project.action_safe_area_vertical) diff --git a/pitivi/viewer/title_overlay.py b/pitivi/viewer/title_overlay.py index 2a785c8cb..7104ab3f3 100644 --- a/pitivi/viewer/title_overlay.py +++ b/pitivi/viewer/title_overlay.py @@ -30,6 +30,7 @@ class TitleOverlay(Overlay): self.__size = None self.__click_window_position = None self.update_from_source() + self.set_draw_func(self.draw_func) stack.app.project_manager.current_project.pipeline.connect("async-done", self.on_async_done) @@ -116,7 +117,7 @@ class TitleOverlay(Overlay): self.__set_source_position(title_position) self._commit() - def do_draw(self, cr): + def draw_func(self, unused_drawing_area, cr, unused_width, unused_height): selected = self._is_selected() hovered = self._is_hovered() if not selected and not hovered: -- GitLab From 28585b1159b0602e794b282321dead5acbcb69d2 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sun, 4 Jun 2023 16:09:45 +0530 Subject: [PATCH 102/132] GtkFileChooser: fix import in medialibrary --- pitivi/medialibrary.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 3d48639fc..69e6054fd 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -65,6 +65,11 @@ from pitivi.utils.ui import SPACING # from pitivi.mediafilespreviewer import PreviewWidget # from pitivi.utils.ui import filter_unsupported_media_files +SUPPORTED_EXTENSIONS = ["3g2", "3gp", "asf", "asx", "av1", "avi", "dv", "flv", "m2t", "m2ts", "m2v", "m4v", + "mkv", "mov", "mp2", "mp4", "mpg", "mpeg", "mts", "mxf", "ogg", "ogv", "rm", "rmvb", + "ts", "vob", "webm", "wmv", "png", "jpg", "jpeg", "gif", "bmp", "svg", "svgz", "tiff", + "tif", "ico", "xpm", "pbm", "pgm", "ppm", "rgb", "xbm", "xpm", "xwd"] + class ViewType(IntEnum): """How the assets can be displayed.""" @@ -830,8 +835,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable): # Filter for the "known good" formats by default file_filter = Gtk.FileFilter() file_filter.set_name(_("Supported file formats")) - # file_filter.add_custom(Gtk.FileFilterFlags.URI | Gtk.FileFilterFlags.MIME_TYPE, - # filter_unsupported_media_files) + + for extension in SUPPORTED_EXTENSIONS: + file_filter.add_pattern("*.%s" % extension) + for formatter in GES.list_assets(GES.Formatter): for extension in formatter.get_meta("extension").split(","): if not extension: @@ -1105,14 +1112,14 @@ class MediaLibraryWidget(Gtk.Box, Loggable): def _import_dialog_box_response_cb(self, dialogbox, response, filechooserwidget, extra_widgets): self.debug("response: %r", response) if response == Gtk.ResponseType.OK: - lastfolder = filechooserwidget.get_current_folder() + lastfolder = filechooserwidget.get_current_folder().get_path() # get_current_folder() is None if file was chosen from 'Recents' if not lastfolder: lastfolder = GLib.path_get_dirname(filechooserwidget.get_filename()) self.app.settings.lastImportFolder = lastfolder extra_widgets.save_values() - gfile = filechooserwidget.get_file() - filenames = gfile.get_uri() + gfiles = filechooserwidget.get_files() + filenames = [gfile.get_uri() for gfile in gfiles] self._project.add_uris(filenames) if self.app.settings.closeImportDialog: dialogbox.destroy() -- GitLab From 13f59f006b327df84e5d87a129480891138544db Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Mon, 5 Jun 2023 16:58:02 +0530 Subject: [PATCH 103/132] Adapt to GtkPopover changes --- pitivi/interactiveintro.py | 2 +- pitivi/medialibrary.py | 3 ++- pitivi/timeline/layer.py | 2 +- pitivi/timeline/markers.py | 2 +- pitivi/timeline/timeline.py | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pitivi/interactiveintro.py b/pitivi/interactiveintro.py index 90e386831..3a3913e0b 100644 --- a/pitivi/interactiveintro.py +++ b/pitivi/interactiveintro.py @@ -172,7 +172,7 @@ class InteractiveIntro(GObject.Object): self.control_popover = Gtk.Popover() self.control_popover.set_name("control-popover") self.control_popover.set_child(vbox) - self.control_popover.set_relative_to(self.intro_button) + self.intro_button.set_child(self.control_popover) self.control_popover.popup() self.control_popover.connect("closed", self._control_popover_closed_cb) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 69e6054fd..fb2574c53 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -1622,7 +1622,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable): self.debug("Not showing popup menu") return - popover = Gtk.Popover.new_from_model(self.flowbox, model) + popover = Gtk.PopoverMenu.new_from_model(model) + self.flowbox.append(popover) popover.insert_action_group("assets", action_group) popover.props.position = Gtk.PositionType.BOTTOM diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 0c5bc87aa..72ea6e4b8 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -97,7 +97,7 @@ class LayerControls(Gtk.Box, Loggable): self.menubutton.props.valign = Gtk.Align.CENTER self.menubutton.set_has_frame(False) model, action_group = self.__create_menu_model() - popover = Gtk.Popover.new_from_model(self.menubutton, model) + popover = Gtk.PopoverMenu.new_from_model(model) popover.insert_action_group("layer", action_group) popover.props.position = Gtk.PositionType.LEFT self.menubutton.set_popover(popover) diff --git a/pitivi/timeline/markers.py b/pitivi/timeline/markers.py index 0fac0150a..06a3a4c83 100644 --- a/pitivi/timeline/markers.py +++ b/pitivi/timeline/markers.py @@ -345,7 +345,7 @@ class MarkerPopover(Gtk.Popover): self.comment_textview.get_buffer().set_text(self.marker.comment) self.set_position(Gtk.PositionType.TOP) - self.set_relative_to(self.marker) + self.marker.append(self) @Gtk.Template.Callback() def remove_button_clicked_cb(self, event): diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 6d195183e..f210c6150 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -2382,7 +2382,8 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): def __add_effect_cb(self, unused_action, unused_parameter): clip = self.timeline.selection.get_single_clip() if clip: - self.effects_popover.set_relative_to(clip.ui) + # self.effects_popover.set_relative_to(clip.ui)\ + clip.ui.set_child(self.effects_popover) self.effects_popover.popup() def _align_selected_cb(self, unused_action, unused_parameter): -- GitLab From 07c0218226d326c1c5fec5d9b3a58ddd8c7c6f42 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Wed, 24 May 2023 12:38:08 +0530 Subject: [PATCH 104/132] GtkHeaderBar: fix title widget --- pitivi/trackerperspective.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index d220fd93b..6db2d23e0 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -658,7 +658,8 @@ class TrackerPerspective(Perspective): back_button.connect("clicked", self.__back_button_clicked_cb) back_button.set_margin_end(4 * PADDING) headerbar.pack_start(back_button) - headerbar.props.title_widget = os.path.basename(self.asset.props.id) + asset_name = os.path.basename(self.asset.props.id) + headerbar.set_title_widget(Gtk.Label.new(asset_name)) headerbar.add_css_class("title") return headerbar -- GitLab From 8ca8227550880a6e3ae21f27dbe2b2bb9f69eb83 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Thu, 8 Jun 2023 20:39:16 +0530 Subject: [PATCH 105/132] Drop use of deprecated pixbuf based api --- pitivi/mediafilespreviewer.py | 6 +++--- pitivi/utils/widgets.py | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index 8b2e03cd4..cef0c637a 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -404,9 +404,9 @@ class PreviewWidget(Gtk.Grid, Loggable): self.settings.FCpreviewWidth = int(w) self.settings.FCpreviewHeight = int(h) elif self.current_preview_type == 'image': - pixbuf = self.preview_image.get_pixbuf() - w = pixbuf.get_width() - h = pixbuf.get_height() + paintable = self.preview_image.get_paintable() + w = paintable.get_intrinsic_width() + h = paintable.get_intrinsic_height() if increment > 0: w *= 1.2 h *= 1.2 diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 030d73ed0..ba42a7a25 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -1441,14 +1441,13 @@ class ColorPickerButton(Gtk.Button): return cursor def button_release_event_cb(self, controller, n_pressed, x, y): - event = controller.get_current_event() - self.grab_color_at_pointer(event.get_display(), x, y) + cursor = controller.get_current_event().get_surface().get_cursor() + self.grab_color_at_pointer(cursor.get_texture(), x, y) self.emit("value-changed") self.shutdown_eyedropper() - def grab_color_at_pointer(self, screen, x, y): - root_window = screen.get_root_window() - pixbuf = Gdk.pixbuf_get_from_window(root_window, x, y, 1, 1) + def grab_color_at_pointer(self, texture, unused_x, unused_y): + pixbuf = Gdk.pixbuf_get_from_texture(texture) pixels = pixbuf.get_pixels() self.color_r = pixels[0] self.color_g = pixels[1] -- GitLab From 6e0a5d5c8dc0952f04e457f17dd4d81f2304937e Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sun, 11 Jun 2023 18:28:58 +0530 Subject: [PATCH 106/132] signal-replacement: replace configure-event signal --- pitivi/mainwindow.py | 14 +++++++++----- pitivi/tabsmanager.py | 11 +++++------ pitivi/viewer/viewer.py | 19 ++++++++++--------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index dd8ecf6fc..9fd4bebfc 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -149,7 +149,8 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): self.check_screen_constraints() - self.connect("configure-event", self.__configure_cb) + self.connect("notify::default-width", self.__configure_width_cb) + self.connect("notify::default-height", self.__configure_height_cb) self.connect("close_request", self.__delete_cb) def __initial_placement_cb(self, width, height): @@ -228,13 +229,16 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): dialog.set_modal(True) dialog.show() - def __configure_cb(self, unused_widget, unused_event): - """Saves the main window size.""" - size_width = self.get_width() + def __configure_height_cb(self, unused_widget, unused_pspec): + """Saves the main window height.""" size_height = self.get_height() - self.app.settings.mainWindowWidth = size_width self.app.settings.mainWindowHeight = size_height + def __configure_width_cb(self, unused_widget, unused_pspec): + """Saves the main window width.""" + size_width = self.get_width() + self.app.settings.mainWindowWidth = size_width + def __delete_cb(self, unused_event): self.app.settings.mainWindowHPanePosition = self.editor.secondhpaned.get_position() self.app.settings.mainWindowMainHPanePosition = self.editor.mainhpaned.get_position() diff --git a/pitivi/tabsmanager.py b/pitivi/tabsmanager.py index 0cc20ec3c..3765b3ae5 100644 --- a/pitivi/tabsmanager.py +++ b/pitivi/tabsmanager.py @@ -109,21 +109,20 @@ class BaseTabs(Gtk.Notebook, Loggable): notebook.props.show_tabs = False window.set_child(notebook) window.move(x, y) - window.connect( - "configure-event", self.__detached_window_configure_cb, - child_name) + window.connect("notify::default-width", self.__detached_window_configure_cb, child_name) + window.connect("notify::default-height", self.__detached_window_configure_cb, child_name) window.connect( "destroy", self.__detached_window_destroyed_cb, child, original_position, child_name) return notebook - def __detached_window_configure_cb(self, window, event, child_name): + def __detached_window_configure_cb(self, window, unused_pspec, child_name): """Saves the position and size of the specified window.""" # get_position() takes the window manager's decorations into account position = window.get_position() - setattr(self.settings, child_name + "width", event.width) - setattr(self.settings, child_name + "height", event.height) + setattr(self.settings, child_name + "width", window.get_width()) + setattr(self.settings, child_name + "height", window.get_height()) setattr(self.settings, child_name + "x", position[0]) setattr(self.settings, child_name + "y", position[1]) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index c5aba7539..d44b4c334 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -222,11 +222,12 @@ class ViewerContainer(Gtk.Box, Loggable): self.dock() return True - def _external_window_configure_cb(self, unused_window, event): - self.settings.viewerWidth = event.width - self.settings.viewerHeight = event.height - self.settings.viewerX = event.x - self.settings.viewerY = event.y + # TODO: Porting: set viewerX and viewerY in the settings + def _external_window_notify_default_width_cb(self, external_window, unused_pspec): + self.settings.viewerWidth = external_window.get_default_width() + + def _external_window_notify_default_height_cb(self, external_window, unused_pspec): + self.settings.viewerHeight = external_window.get_default_height() def _create_ui(self): """Creates the Viewer GUI.""" @@ -239,8 +240,8 @@ class ViewerContainer(Gtk.Box, Loggable): self.external_window.set_child(vbox) self.external_window.connect( "close_request", self._external_window_close_cb) - self.external_window.connect( - "configure-event", self._external_window_configure_cb) + self.external_window.connect("notify::default-width", self._external_window_notify_default_width_cb) + self.external_window.connect("notify::default-height", self._external_window_notify_default_height_cb) self.external_vbox = vbox # This holds the viewer and the peak meters box. @@ -294,7 +295,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.peak_meter_scale.set_margin_start(SPACING) self.peak_meter_box.append(self.peak_meter_scale) self.viewer_row_box.append(self.peak_meter_box) - self.peak_meter_scale.connect("configure-event", self.__peak_meter_scale_configure_event_cb) + self.peak_meter_scale.connect("notify::content_height", self.__peak_meter_scale_notify_content_height_cb) # Buttons/Controls bbox = Gtk.Box() @@ -466,7 +467,7 @@ class ViewerContainer(Gtk.Box, Loggable): hpane.set_position(x - self.__translation[0]) vpane.set_position(y - self.__translation[1]) - def __peak_meter_scale_configure_event_cb(self, unused_widget, unused_event): + def __peak_meter_scale_notify_content_height_cb(self, unused_widget, unused_event): container_height = self.viewer_row_box.get_allocated_height() margins = self.peak_meter_box.get_allocated_height() - self.peak_meter_scale.get_bar_height() + SPACING * 4 -- GitLab From 1f21dfea3485921e0dd0dc4176cf306a49637207 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 13 Jun 2023 17:37:39 +0530 Subject: [PATCH 107/132] WIP:signal-replacement: remove size-allocatesignal --- pitivi/timeline/timeline.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index f210c6150..2750fcdd1 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -256,7 +256,7 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): self.marquee = Marquee(timeline, self) self.fixed.put(self.marquee, 0, 0) - self.layers_vbox.connect("size-allocate", self.__size_allocate_cb) + # self.layers_vbox.connect("size-allocate", self.__size_allocate_cb) def do_snapshot(self, snapshot): """Draws the children and indicators.""" @@ -292,12 +292,12 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): cr.line_to(xpos, height) cr.stroke() - def __size_allocate_cb(self, unused_widget, allocation): - """Sets the size of the scrollable area to fit the layers_vbox.""" - self.log("The size of the layers_vbox changed: %sx%s", allocation.width, allocation.height) - # The additional space is for the 'Add layer' button. - self.set_max_content_width(allocation.width) - self.set_max_content_height(allocation.height + LAYER_HEIGHT / 2) + # def __size_allocate_cb(self, unused_widget, allocation): + # """Sets the size of the scrollable area to fit the layers_vbox.""" + # self.log("The size of the layers_vbox changed: %sx%s", allocation.width, allocation.height) + # # The additional space is for the 'Add layer' button. + # self.set_max_content_width(allocation.width) + # self.set_max_content_height(allocation.height + LAYER_HEIGHT / 2) class FullLayersLayout(LayersLayout, Zoomable): @@ -532,14 +532,15 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.app.settings.connect("edgeSnapDeadbandChanged", self.__snap_distance_changed_cb) - self.layout.layers_vbox.connect_after("size-allocate", self.__size_allocate_cb) + # self.layout.layers_vbox.connect_after("size-allocate", self.__size_allocate_cb) + self.layers_size_group = Gtk.SizeGroup.new(Gtk.SizeGroupMode.VERTICAL) self.hadj.connect("value-changed", self.__hadj_value_changed_cb) - def __size_allocate_cb(self, unused_widget, unused_allocation): - """Handles the layers vbox size allocations.""" - if self.delayed_scroll: - self.scroll_to_playhead(**self.delayed_scroll) + # def __size_allocate_cb(self, unused_widget, unused_allocation): + # """Handles the layers vbox size allocations.""" + # if self.delayed_scroll: + # self.scroll_to_playhead(**self.delayed_scroll) @property def media_types(self): @@ -1294,12 +1295,14 @@ class Timeline(Gtk.Box, Zoomable, Loggable): control = LayerControls(ges_layer, self.app) self._layers_controls_vbox.prepend(control) + self.layers_size_group.add_widget(control) ges_layer.control_ui = control # Check the media types so the controls are set up properly. layer.check_media_types() mini_layer.check_media_types() self.layout.layers_vbox.prepend(layer) + self.layers_size_group.add_widget(layer) layer.show() self.mini_layout.layers_vbox.prepend(mini_layer) @@ -1674,7 +1677,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): self._create_ui() self._create_actions() - self.timeline.connect("size-allocate", self.__timeline_size_allocate_cb) + # self.timeline.connect("size-allocate", self.__timeline_size_allocate_cb) # Public API @@ -2551,9 +2554,9 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable): self.log("Timeline has lost focus") self.update_actions() - def __timeline_size_allocate_cb(self, unused_widget, allocation): - fits = self.timeline.layout.props.height <= allocation.height - self.vscrollbar.set_opacity(0 if fits else 1) + # def __timeline_size_allocate_cb(self, unused_widget, allocation): + # fits = self.timeline.layout.props.height <= allocation.height + # self.vscrollbar.set_opacity(0 if fits else 1) def _zoom_in_cb(self, unused_action, unused_parameter): Zoomable.zoom_in() -- GitLab From d0b6f86072c3345bbdc05497d12deedfa0525565 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sat, 10 Jun 2023 16:15:42 +0530 Subject: [PATCH 108/132] Adapt to GtkNotebook API changes --- pitivi/tabsmanager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pitivi/tabsmanager.py b/pitivi/tabsmanager.py index 3765b3ae5..9584af17b 100644 --- a/pitivi/tabsmanager.py +++ b/pitivi/tabsmanager.py @@ -62,9 +62,10 @@ class BaseTabs(Gtk.Notebook, Loggable): child.show() def _set_child_properties(self, child, label): - self.child_set_property(child, "detachable", True) - self.child_set_property(child, "tab-expand", False) - self.child_set_property(child, "tab-fill", True) + page = self.get_page(child) + page.props.detachable = True + page.props.tab_expand = False + page.props.tab_fill = True label.props.xalign = 0.0 def __detached_window_destroyed_cb(self, window, child, -- GitLab From 1d1777a57f525b946c09c792778e33a1bf414b52 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sat, 10 Jun 2023 16:52:30 +0530 Subject: [PATCH 109/132] GtkWidget: remove deprecated GtkWidget::add_events --- pitivi/clip_properties/alignment.py | 2 -- pitivi/dialogs/prefs.py | 1 - pitivi/timeline/markers.py | 7 ------- pitivi/timeline/ruler.py | 4 ---- pitivi/timeline/timeline.py | 3 --- pitivi/utils/widgets.py | 1 - pitivi/viewer/overlay_stack.py | 7 ------- pitivi/viewer/viewer.py | 4 ---- 8 files changed, 29 deletions(-) diff --git a/pitivi/clip_properties/alignment.py b/pitivi/clip_properties/alignment.py index 334b83407..7eaca297b 100644 --- a/pitivi/clip_properties/alignment.py +++ b/pitivi/clip_properties/alignment.py @@ -16,7 +16,6 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . -from gi.repository import Gdk from gi.repository import GObject from gi.repository import Graphene from gi.repository import Gtk @@ -50,7 +49,6 @@ class AlignmentEditor(Gtk.Box, Loggable): eventcontroller_motion.connect("leave", self._leave_notify_event_cb) self.add_controller(eventcontroller_click) self.add_controller(eventcontroller_motion) - self.add_events(Gdk.EventMask.POINTER_MOTION_MASK) def _leave_notify_event_cb(self, controller): self._hovered_box = None diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 48393b068..002d92715 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -633,7 +633,6 @@ class CustomShortcutDialog(Gtk.Dialog): self.set_geometry_hints(None, geometry, Gdk.WindowHints.MAX_SIZE) self.set_transient_for(self.preferences) self.get_titlebar().set_decoration_layout('close:') - self.add_events(Gdk.EventMask.KEY_PRESS_MASK) self.conflicting_action = None diff --git a/pitivi/timeline/markers.py b/pitivi/timeline/markers.py index 06a3a4c83..4efdf5bb2 100644 --- a/pitivi/timeline/markers.py +++ b/pitivi/timeline/markers.py @@ -39,9 +39,6 @@ class Marker(Gtk.Box, Loggable): Gtk.Box.__init__(self) Loggable.__init__(self) - self.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | - Gdk.EventMask.LEAVE_NOTIFY_MASK) - self.ges_marker = ges_marker self.ges_marker.ui = self self.position_ns = self.ges_marker.props.position @@ -128,10 +125,6 @@ class MarkersBox(Gtk.Box, Zoomable, Loggable): self.marker_moving: Optional[Marker] = None self.marker_new: Optional[Marker] = None - self.add_events(Gdk.EventMask.POINTER_MOTION_MASK | - Gdk.EventMask.BUTTON_PRESS_MASK | - Gdk.EventMask.BUTTON_RELEASE_MASK) - def first_marker(self, before: Optional[int] = None, after: Optional[int] = None) -> Optional[int]: """Returns position of the closest marker found before or after the given timestamp. diff --git a/pitivi/timeline/ruler.py b/pitivi/timeline/ruler.py index 2e187fef1..024202b2f 100644 --- a/pitivi/timeline/ruler.py +++ b/pitivi/timeline/ruler.py @@ -104,10 +104,6 @@ class ScaleRuler(Gtk.DrawingArea, Loggable): self._pipeline = None self.ges_timeline = None - self.add_events(Gdk.EventMask.POINTER_MOTION_MASK | - Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | - Gdk.EventMask.SCROLL_MASK) - self.pixbuf = None # all values are in pixels diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 2750fcdd1..dfbb1389b 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -407,7 +407,6 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.mini_layout_container = Gtk.Box.new() self.mini_layout_container.append(self.mini_layout) - self.mini_layout_container.add_events(Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE) self.mini_layout_container.props.height_request = MINI_LAYER_HEIGHT self.mini_layout_container.hide() @@ -440,8 +439,6 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.set_name("timeline canvas") assert self.get_has_window() - # A lot of operations go through the handlers of these events. - self.add_events(Gdk.EventType.BUTTON_PRESS | Gdk.EventType.BUTTON_RELEASE) # Whether the entire timeline content is in view and # it should be kept that way if it makes sense. diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index ba42a7a25..0777f78bd 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -1407,7 +1407,6 @@ class ColorPickerButton(Gtk.Button): grab_widget.resize(1, 1) grab_widget.move(-100, -100) grab_widget.show() - grab_widget.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK) top_level = self.get_toplevel() if isinstance(top_level, Gtk.Window): if top_level.has_group(): diff --git a/pitivi/viewer/overlay_stack.py b/pitivi/viewer/overlay_stack.py index 349f4204d..1e0b6fe80 100644 --- a/pitivi/viewer/overlay_stack.py +++ b/pitivi/viewer/overlay_stack.py @@ -41,13 +41,6 @@ class OverlayStack(Gtk.Overlay, Loggable): self.click_position = None self.hovered_overlay = None self.selected_overlay = None - self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | - Gdk.EventMask.BUTTON_RELEASE_MASK | - Gdk.EventMask.POINTER_MOTION_MASK | - Gdk.EventMask.SCROLL_MASK | - Gdk.EventMask.ENTER_NOTIFY_MASK | - Gdk.EventMask.LEAVE_NOTIFY_MASK | - Gdk.EventMask.ALL_EVENTS_MASK) self.set_child(sink_widget) self.connect("size-allocate", self.__size_allocate_cb) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index d44b4c334..c29324af6 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -259,10 +259,6 @@ class ViewerContainer(Gtk.Box, Loggable): corner_size = space * lines + margin corner.set_size_request(corner_size, corner_size) corner.set_halign(Gtk.Align.START) - corner.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | - Gdk.EventMask.BUTTON_PRESS_MASK | - Gdk.EventMask.BUTTON_RELEASE_MASK | - Gdk.EventMask.POINTER_MOTION_MASK) hpane = self.app.gui.editor.mainhpaned vpane = self.app.gui.editor.toplevel_widget -- GitLab From bdbf59cddbb103955a5b551de4739735a37971c1 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Mon, 12 Jun 2023 16:27:37 +0530 Subject: [PATCH 110/132] timeline: replace deprecated methods and props from GtkEventBox --- pitivi/timeline/timeline.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index dfbb1389b..fc0e263cc 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -405,7 +405,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.mini_layout = MiniLayersLayout(self) - self.mini_layout_container = Gtk.Box.new() + self.mini_layout_container = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) self.mini_layout_container.append(self.mini_layout) self.mini_layout_container.props.height_request = MINI_LAYER_HEIGHT self.mini_layout_container.hide() @@ -435,11 +435,10 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self._layers_controls_vbox.append(self.add_layer_button) self.add_css_class("Timeline") - self.props.expand = True + self.set_hexpand(True) + self.set_vexpand(True) self.set_name("timeline canvas") - assert self.get_has_window() - # Whether the entire timeline content is in view and # it should be kept that way if it makes sense. self.zoomed_fitted = True -- GitLab From 31896248b034ed8033034aa974328254783b9cef Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Mon, 12 Jun 2023 17:23:06 +0530 Subject: [PATCH 111/132] mainwindow: (TODO: fix later)temp remove unecessary things --- pitivi/mainwindow.py | 9 +++------ pitivi/timeline/timeline.py | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 9fd4bebfc..5fb5e9c17 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -142,10 +142,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): # a bit different than opening `pitivi file.xges`. For example # connecting to the "realize" signal instead of idle_add-ing # fails to restore the position when directly loading a project. - GLib.idle_add(self.__initial_placement_cb, - self.app.settings.mainWindowX, - self.app.settings.mainWindowY, - width, height) + GLib.idle_add(self.__initial_placement_cb, width, height) self.check_screen_constraints() @@ -175,8 +172,8 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): # a way, even with client-side decorations, to tell us the exact # minimum required dimensions of a window. min_size, _ = self.get_preferred_size() - screen_width = self.get_screen().get_width() - screen_height = self.get_screen().get_height() + screen_width = self.get_width() + screen_height = self.get_height() self.debug("Minimum UI size is %sx%s", min_size.width, min_size.height) self.debug("Screen size is %sx%s", screen_width, screen_height) return min_size.width >= 0.9 * screen_width diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index fc0e263cc..cac089b40 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -505,9 +505,9 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.__last_clips_on_leave = None # To be able to receive effects dragged on clips. - drop_target = Gtk.DropTarget.new(GObject.TYPE_INVALID, Gdk.DragAction.COPY) + drop_target = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) drop_target.set_gtypes([GObject.TYPE_STRING, Gdk.FileList]) - mini_layout_controller = Gtk.DropTarget.new(GObject.TYPE_INVALID, Gdk.DragAction.COPY) + mini_layout_controller = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) mini_layout_controller.set_gtypes([GObject.TYPE_STRING, Gdk.FileList]) drop_target.connect("accept", self._accept_cb) -- GitLab From e4d5779a21f56e2acf1a335ce0c2aba4efd9ae91 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 13 Jun 2023 19:29:30 +0530 Subject: [PATCH 112/132] GtkWidget: use if_focus() --- pitivi/editorperspective.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 10b251aad..3cfc1f07e 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -318,7 +318,7 @@ class EditorPerspective(Perspective, Loggable): def focus_timeline(self): layers_representation = self.timeline_ui.timeline.layout # Check whether it has focus already, grab_focus always emits an event. - if not layers_representation.props.is_focus: + if not layers_representation.is_focus(): layers_representation.grab_focus() def __create_headerbar(self): -- GitLab From 5edcc8bd75bc5fd0715f35b70d4f40cfb39e7e64 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Thu, 15 Jun 2023 16:30:42 +0530 Subject: [PATCH 113/132] GtkLayout: replace deprecated add() function --- pitivi/timeline/elements.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 5fb5d9437..8bce51673 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -669,16 +669,16 @@ class TimelineElement(Gtk.Fixed, Zoomable, Loggable): self.previewer = self._get_previewer() if self.previewer: - self.add(self.previewer) + self.put(self.previewer, 0, 0) self.__background = self._get_background() if self.__background: - self.add(self.__background) + self.put(self.__background, 0, 0) self.markers = ClipMarkersBox(self.app, self._ges_elem) self._ges_elem.markers_manager.set_markers_box(self.markers) - self.add(self.markers) + self.put(self.markers, 0, 0) self.keyframe_curve = None self.__controlled_property = None -- GitLab From 202012b9fe204049ea76782f4ea7ddfe43f49dd0 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Mon, 19 Jun 2023 22:33:38 +0530 Subject: [PATCH 114/132] GtkSink:[WIP]: GtkSink replacement --- pitivi/check.py | 10 +++++----- pitivi/trackerperspective.py | 4 ++-- pitivi/utils/pipeline.py | 8 +++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pitivi/check.py b/pitivi/check.py index c74529b6c..b7131a91f 100644 --- a/pitivi/check.py +++ b/pitivi/check.py @@ -272,12 +272,12 @@ def _check_videosink(): from gi.repository import Gst global VIDEOSINK_FACTORY - # If using GdkBroadwayDisplay make sure not to try to use gtkglsink + # If using GdkBroadwayDisplay make sure not to try to use gtk4glsink # as it would segfault right away. if not VIDEOSINK_FACTORY and \ not _using_broadway_display() and \ - "gtkglsink" in os.environ.get("PITIVI_UNSTABLE_FEATURES", ""): - sink = Gst.ElementFactory.make("gtkglsink", None) + "gtk4glsink" in os.environ.get("PITIVI_UNSTABLE_FEATURES", ""): + sink = Gst.ElementFactory.make("gtk4glsink", None) if sink: res = sink.set_state(Gst.State.READY) if res == Gst.StateChangeReturn.SUCCESS: @@ -285,7 +285,7 @@ def _check_videosink(): sink.set_state(Gst.State.NULL) if not VIDEOSINK_FACTORY: - VIDEOSINK_FACTORY = Gst.ElementFactory.find("gtksink") + VIDEOSINK_FACTORY = Gst.ElementFactory.find("gtk4paintablesink") return VIDEOSINK_FACTORY @@ -355,7 +355,7 @@ def check_requirements(): if not _check_videosink(): print(_("Could not create video output sink. " - "Make sure you have a gtksink available.")) + "Make sure you have a gtk4paintablesink available.")) return False _check_hardware_decoders() diff --git a/pitivi/trackerperspective.py b/pitivi/trackerperspective.py index 6db2d23e0..ebd9d2016 100644 --- a/pitivi/trackerperspective.py +++ b/pitivi/trackerperspective.py @@ -537,7 +537,7 @@ class ToplevelWidget(Gtk.Box, Loggable): "uridecodebin uri={} ! videoconvert ! \ cvtracker object-initial-x={} object-initial-y={} object-initial-width={} \ object-initial-height={} algorithm={} draw-rect=true ! tee name=t ! \ - queue ! videoconvert ! gtksink name=gtksink t. \ + queue ! videoconvert ! gtk4paintablesink name=gtk4paintablesink t. \ ! fakesink name=sink signal-handoffs=TRUE" .format(self.asset.props.id, int(x), int(y), int(w), int(h), algorithm)) @@ -548,7 +548,7 @@ class ToplevelWidget(Gtk.Box, Loggable): fakesink.connect("handoff", self.__tracker_handoff_cb, self.roi_data) # Set up a widget to show the video as the object is being tracked. - video_sink = _pipeline.get_by_name("gtksink") + video_sink = _pipeline.get_by_name("gtk4paintablesink") self.tracker_sink_widget = video_sink.props.widget self.viewer_overlay.add_overlay(self.tracker_sink_widget) diff --git a/pitivi/utils/pipeline.py b/pitivi/utils/pipeline.py index 354e8c909..0f16c817c 100644 --- a/pitivi/utils/pipeline.py +++ b/pitivi/utils/pipeline.py @@ -22,6 +22,7 @@ from gi.repository import GES from gi.repository import GLib from gi.repository import GObject from gi.repository import Gst +from gi.repository import Gtk from pitivi.check import VIDEOSINK_FACTORY from pitivi.utils.loggable import Loggable @@ -106,10 +107,11 @@ class SimplePipeline(GObject.Object, Loggable): """ factory_name = VIDEOSINK_FACTORY.get_name() sink = Gst.ElementFactory.make(factory_name, None) - widget = sink.props.widget + paintable = sink.props.paintable + widget = Gtk.Picture.new_for_paintable(paintable) - if factory_name == "gtksink": - self.info("Using gtksink") + if factory_name == "gtk4paintablesink": + self.info("Using gtk4paintablesink") video_sink = sink else: self.info("Using glsinkbin around %s", VIDEOSINK_FACTORY.get_name()) -- GitLab From 13e4ff6a175891a1118bc5026430209525427af6 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 20 Jun 2023 15:18:08 +0530 Subject: [PATCH 115/132] GtkEventController: replace deprecated get_widget() method --- pitivi/timeline/timeline.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index cac089b40..ce798f2ab 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -533,10 +533,10 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.hadj.connect("value-changed", self.__hadj_value_changed_cb) - # def __size_allocate_cb(self, unused_widget, unused_allocation): - # """Handles the layers vbox size allocations.""" - # if self.delayed_scroll: - # self.scroll_to_playhead(**self.delayed_scroll) + def __size_allocate_cb(self, unused_widget, unused_allocation): + """Handles the layers vbox size allocations.""" + if self.delayed_scroll: + self.scroll_to_playhead(**self.delayed_scroll) @property def media_types(self): @@ -850,7 +850,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.debug("PRESSED %s", controller) self.app.gui.editor.focus_timeline() - event_widget = Gtk.get_widget(controller) + event_widget = controller.get_widget() button = controller.get_button() if button == 1: @@ -1340,10 +1340,10 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.debug("Layers still being shuffled, not updating widgets: %s", priorities) return self.debug("Updating layers widgets positions") - self.__update_separator(0) - for ges_layer in ges_layers: - self.__update_layer(ges_layer) - self.__update_separator(ges_layer.props.priority + 1) + # self.__update_separator(0) + # for ges_layer in ges_layers: + # self.__update_layer(ges_layer) + # self.__update_separator(ges_layer.props.priority + 1) def __update_separator(self, priority): """Sets the position of the separators in their parent.""" -- GitLab From 3732b6d723b31048476ea1bad87f68f278813e51 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 20 Jun 2023 15:42:12 +0530 Subject: [PATCH 116/132] Preferences: fix preferences --- pitivi/dialogs/prefs.py | 2 +- pitivi/mainwindow.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pitivi/dialogs/prefs.py b/pitivi/dialogs/prefs.py index 002d92715..24a5aace2 100644 --- a/pitivi/dialogs/prefs.py +++ b/pitivi/dialogs/prefs.py @@ -605,7 +605,7 @@ class ModelItem(GObject.Object): except IndexError: accels = "" - keyval, mods = Gtk.accelerator_parse(accels) + unused_bool, keyval, mods = Gtk.accelerator_parse(accels) return Gtk.accelerator_get_label(keyval, mods) diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py index 5fb5e9c17..ef3229dfc 100644 --- a/pitivi/mainwindow.py +++ b/pitivi/mainwindow.py @@ -223,8 +223,7 @@ class MainWindow(Gtk.ApplicationWindow, Loggable): def __preferences_cb(self, unused_action, unused_param): dialog = PreferencesDialog(self.app) - dialog.set_modal(True) - dialog.show() + dialog.run() def __configure_height_cb(self, unused_widget, unused_pspec): """Saves the main window height.""" -- GitLab From c0eb053871cb12e640a8de67e6098b3190cc5ece Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sat, 10 Jun 2023 18:30:26 +0530 Subject: [PATCH 117/132] TempFix:[WIP] To be replaced --- pitivi/check.py | 4 ++-- pitivi/timeline/timeline.py | 10 +++++----- pitivi/utils/ui.py | 10 +++++----- pitivi/viewer/overlay_stack.py | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pitivi/check.py b/pitivi/check.py index b7131a91f..940a76b45 100644 --- a/pitivi/check.py +++ b/pitivi/check.py @@ -392,8 +392,8 @@ def initialize_modules(): Gtk.init() # Monkey patch deprecated methods to use the new variant by default - Gtk.Layout.get_vadjustment = Gtk.Scrollable.get_vadjustment - Gtk.Layout.get_hadjustment = Gtk.Scrollable.get_hadjustment + # Gtk.Layout.get_vadjustment = Gtk.Scrollable.get_vadjustment + # Gtk.Layout.get_hadjustment = Gtk.Scrollable.get_hadjustment if not gi.version_info >= (3, 11): from gi.repository import GObject diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index ce798f2ab..e7d962ed3 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -396,7 +396,6 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.layout = FullLayersLayout(self) self.layout.props.can_focus = True - self.layout.props.can_default = True self.layout.set_hexpand(True) self.layout.set_halign(Gtk.Align.FILL) self.hadj = self.layout.get_hadjustment() @@ -533,10 +532,11 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.hadj.connect("value-changed", self.__hadj_value_changed_cb) - def __size_allocate_cb(self, unused_widget, unused_allocation): - """Handles the layers vbox size allocations.""" - if self.delayed_scroll: - self.scroll_to_playhead(**self.delayed_scroll) + # TODO: Find replacement for set_child_property + # def __size_allocate_cb(self, unused_widget, unused_allocation): + # """Handles the layers vbox size allocations.""" + # if self.delayed_scroll: + # self.scroll_to_playhead(**self.delayed_scroll) @property def media_types(self): diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py index bad615b71..54adff35b 100644 --- a/pitivi/utils/ui.py +++ b/pitivi/utils/ui.py @@ -877,9 +877,9 @@ def set_state_flags_recurse(widget, state_flags, are_set, ignored_classes=()): else: widget.unset_state_flags(state_flags) - if isinstance(widget, Gtk.Container): - for child in get_widget_children(widget): - set_state_flags_recurse(child, state_flags, are_set, ignored_classes) + # if isinstance(widget, Gtk.Container): + # for child in get_widget_children(widget): + # set_state_flags_recurse(child, state_flags, are_set, ignored_classes) def disable_scroll_event_cb(controller, dx, dy): @@ -893,8 +893,8 @@ def disable_scroll(widget): Makes sure the vulnerable widgets do not react to scroll events. """ - if isinstance(widget, Gtk.Container): - widget.foreach(disable_scroll) + # if isinstance(widget, Gtk.Container): + # widget.foreach(disable_scroll) if isinstance(widget, (Gtk.ComboBox, Gtk.Scale, Gtk.SpinButton)): eventcontroller_scroll = Gtk.EventControllerScroll() diff --git a/pitivi/viewer/overlay_stack.py b/pitivi/viewer/overlay_stack.py index 1e0b6fe80..734c3cb95 100644 --- a/pitivi/viewer/overlay_stack.py +++ b/pitivi/viewer/overlay_stack.py @@ -42,7 +42,7 @@ class OverlayStack(Gtk.Overlay, Loggable): self.hovered_overlay = None self.selected_overlay = None self.set_child(sink_widget) - self.connect("size-allocate", self.__size_allocate_cb) + # self.connect("size-allocate", self.__size_allocate_cb) # Whether to show the percent of the size relative to the project size. # It is set to false initially because the viewer gets resized @@ -62,7 +62,7 @@ class OverlayStack(Gtk.Overlay, Loggable): self.safe_areas_overlay = SafeAreasOverlay(self) self.add_overlay(self.safe_areas_overlay) - sink_widget.connect("size-allocate", self.__sink_widget_size_allocate_cb) + # sink_widget.connect("size-allocate", self.__sink_widget_size_allocate_cb) def __size_allocate_cb(self, widget, rectangle): self.window_size = numpy.array([rectangle.width, -- GitLab From 1168367ecc017bace66fd75d7cac35d7ac7e8b31 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Thu, 15 Jun 2023 10:59:13 +0530 Subject: [PATCH 118/132] Viewer: Adapt to Gtk4 Api changes --- pitivi/timeline/elements.py | 3 +-- pitivi/viewer/overlay_stack.py | 2 +- pitivi/viewer/viewer.py | 10 +++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 8bce51673..35f9effbc 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -1174,8 +1174,7 @@ class TrimHandle(Gtk.Box, Loggable): def shrink(self): self.props.width_request = TrimHandle.DEFAULT_WIDTH - if self.props.window: - self.props.window.set_cursor(NORMAL_CURSOR) + self.set_cursor(NORMAL_CURSOR) class Clip(Gtk.Box, Loggable): diff --git a/pitivi/viewer/overlay_stack.py b/pitivi/viewer/overlay_stack.py index 734c3cb95..4ced1da34 100644 --- a/pitivi/viewer/overlay_stack.py +++ b/pitivi/viewer/overlay_stack.py @@ -52,7 +52,7 @@ class OverlayStack(Gtk.Overlay, Loggable): # ID of resizing timeout callback, so it can be delayed. self.__resizing_id = 0 self.revealer = Gtk.Revealer(transition_type=Gtk.RevealerTransitionType.CROSSFADE) - self.resize_status = Gtk.Label.new(name="resize_status") + self.resize_status = Gtk.Label.new("resize_status") self.revealer.set_child(self.resize_status) self.add_overlay(self.revealer) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index c29324af6..207f7f1d0 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -436,12 +436,13 @@ class ViewerContainer(Gtk.Box, Loggable): cr.line_to(space * (lines - i), space * lines) cr.stroke() - def __corner_enter_notify_cb(self, widget, unused_event): + def __corner_enter_notify_cb(self, controller, unused_x, unused_y): + widget = controller.get_widget() if not self.__cursor: self.__cursor = Gdk.Cursor.new_from_name("sw-resize") widget.set_cursor(self.__cursor) - def __corner_button_press_cb(self, controller, n_pressed, x, y, data, hpane, vpane): + def __corner_button_press_cb(self, controller, n_pressed, x, y, hpane, vpane): if controller.get_button() == 1: # The mouse pointer position is w.r.t the root of the screen # whereas the positions of panes is w.r.t the root of the @@ -455,7 +456,7 @@ class ViewerContainer(Gtk.Box, Loggable): def __corner_button_release_cb(self, unused_controller, n_pressed, x, y): self.__translation = None - def __corner_motion_notify_cb(self, controller, x, y, data, hpane, vpane): + def __corner_motion_notify_cb(self, controller, x, y, hpane, vpane): if self.__translation is None: return @@ -727,8 +728,7 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): """ def __init__(self, video_widget): - Gtk.AspectFrame.__init__(self, xalign=0.5, yalign=0.5, ratio=4 / 3, - border_width=SPACING, obey_child=False) + Gtk.AspectFrame.__init__(self, xalign=0.5, yalign=0.5, ratio=4 / 3, obey_child=False) Loggable.__init__(self) # The width and height used when snapping the child widget size. -- GitLab From 882e3f7c1deac51c93cdd79542cabf7b9e2a7121 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Thu, 22 Jun 2023 18:42:32 +0530 Subject: [PATCH 119/132] Layer: fix order of widget in layer --- pitivi/timeline/layer.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 72ea6e4b8..6eba691be 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -81,17 +81,17 @@ class LayerControls(Gtk.Box, Loggable): vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.set_vexpand(True) vbox.set_valign(Gtk.Align.FILL) - hbox.prepend(vbox) + hbox.append(vbox) rightside_separator = Gtk.Separator.new(Gtk.Orientation.VERTICAL) - hbox.prepend(rightside_separator) + hbox.append(rightside_separator) name_row = Gtk.Box() name_row.set_orientation(Gtk.Orientation.HORIZONTAL) name_row.props.margin_top = PADDING name_row.props.margin_start = PADDING name_row.props.margin_end = PADDING - vbox.prepend(name_row) + vbox.append(name_row) self.menubutton = Gtk.MenuButton.new() self.menubutton.props.valign = Gtk.Align.CENTER @@ -101,7 +101,7 @@ class LayerControls(Gtk.Box, Loggable): popover.insert_action_group("layer", action_group) popover.props.position = Gtk.PositionType.LEFT self.menubutton.set_popover(popover) - name_row.prepend(self.menubutton) + name_row.append(self.menubutton) self.name_entry = Gtk.Entry() self.name_entry.add_css_class("LayerControlEntry") @@ -113,7 +113,7 @@ class LayerControls(Gtk.Box, Loggable): self.name_entry.add_controller(eventcontroller_focus) self.ges_layer.connect("notify-meta", self.__layer_rename_cb) self.__update_name() - name_row.prepend(self.name_entry) + name_row.append(self.name_entry) self.audio_button = Gtk.Button.new() self.audio_button.connect("clicked", self.__audio_button_clicked_cb) @@ -127,11 +127,11 @@ class LayerControls(Gtk.Box, Loggable): control_box.append(self.video_button) control_box.append(self.audio_button) control_box.add_css_class("linked") - name_row.prepend(control_box) + name_row.append(control_box) space = Gtk.Label() space.props.vexpand = True - vbox.prepend(space) + vbox.append(space) self.ges_layer.connect("notify::priority", self.__layer_priority_changed_cb) self.ges_layer.connect("active-changed", self.__layer_active_changed_cb) -- GitLab From a18c3d8e1a77bec843e6ad3307a29afda40cbdb4 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Sun, 25 Jun 2023 11:13:55 +0530 Subject: [PATCH 120/132] EffectBox: Fix searchbar position --- pitivi/effects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pitivi/effects.py b/pitivi/effects.py index 13533d825..ea094e5fe 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -424,8 +424,8 @@ class EffectListWidget(Gtk.Box, Loggable): scrollwin.set_valign(Gtk.Align.FILL) scrollwin.set_child(self.main_view) - self.prepend(toolbar) self.prepend(scrollwin) + self.prepend(toolbar) # Delay the loading of the available effects so the application # starts faster. -- GitLab From 54b321b2773b2f7155f95cc8282819225eddbb7c Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 27 Jun 2023 17:28:00 +0530 Subject: [PATCH 121/132] DND: fix flow --- pitivi/clipproperties.py | 9 +++++--- pitivi/effects.py | 18 ++++++++-------- pitivi/medialibrary.py | 41 +++++++++++++++++++------------------ pitivi/timeline/timeline.py | 41 +++++++++++++++++++------------------ pitivi/viewer/viewer.py | 24 ++++++++++++++-------- 5 files changed, 73 insertions(+), 60 deletions(-) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index b6465c53f..fcfbf76a0 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -23,12 +23,12 @@ from typing import Dict from typing import Optional from typing import Tuple -import cairo from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import GLib from gi.repository import GObject +from gi.repository import Graphene from gi.repository import Gst from gi.repository import GstController from gi.repository import Gtk @@ -868,12 +868,15 @@ class EffectProperties(Gtk.Expander, Loggable): row = eventbox.get_parent() alloc = row.get_allocation() - paintable = Gdk.Paintable.new_empty(alloc.width, alloc.height) - ctx = cairo.Context(paintable) + snapshot = Gtk.Snapshot.new() + bounds = Graphene.Rect().init(0, 0, alloc.width, alloc.height) + ctx = snapshot.append_cairo(bounds) row.draw(ctx) ctx.paint_with_alpha(0.35) + paintable = snapshot.to_paintable(Graphene.Size().init(alloc.width, alloc.height)) + drag_source.set_icon(paintable, alloc.width / 2, alloc.height / 2) def _prepare_cb(self, drag_source, unused_x, unused_y, eventbox): diff --git a/pitivi/effects.py b/pitivi/effects.py index ea094e5fe..e6441e7a4 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -35,12 +35,12 @@ from gettext import gettext as _ from typing import Optional from typing import Union -import cairo from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import GLib from gi.repository import GObject +from gi.repository import Graphene from gi.repository import Gst from gi.repository import Gtk @@ -534,19 +534,18 @@ class EffectListWidget(Gtk.Box, Loggable): # Set up drag behavoir eventbox = Gtk.Box() + eventbox.append(effect_box) eventbox_controller = Gtk.DragSource.new() eventbox_controller.connect("drag-begin", self._drag_begin_cb) - eventbox_controller.connect("prepare", self._prepare_cb, eventbox) + eventbox_controller.connect("prepare", self._prepare_cb, effect_box) eventbox.add_controller(eventbox_controller) - eventbox.append(effect_box) row = Gtk.ListBoxRow(selectable=False) row.set_child(eventbox) return row - def _prepare_cb(self, drag_source, start_x, start_y, eventbox): - effect_box = eventbox.get_child() + def _prepare_cb(self, drag_source, start_x, start_y, effect_box): data = GObject.Value(GObject.TYPE_STRING) data.set_value(str(effect_box.effect_name)) content_provider = Gdk.ContentProvider.new_for_value(data) @@ -558,15 +557,18 @@ class EffectListWidget(Gtk.Box, Loggable): icon_height = icon.get_height() icon_width = icon.get_width() - paintable = Gdk.Paintable.new_empty(icon_width, icon_height) - ctx = cairo.Context(paintable) + snapshot = Gtk.Snapshot.new() + bounds = Graphene.Rect().init(0, 0, 2 * icon_width, 2 * icon_height) + ctx = snapshot.append_cairo(bounds) # Center the icon around the cursor. ctx.translate(icon_width / 2, icon_height / 2) Gdk.cairo_set_source_pixbuf(ctx, icon, 0, 0) ctx.paint_with_alpha(0.35) - drag_source.set_icon(paintable, icon_width / 2, icon_height / 2) + paintable = snapshot.to_paintable(Graphene.Size().init(2 * icon_width, 2 * icon_height)) + + drag_source.set_icon(paintable, icon_width, icon_height) def effects_listbox_row_activated_cb(self, listbox, row): """Handles the activation of a row representing an effect.""" diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index fb2574c53..7038292ab 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -28,13 +28,13 @@ from gettext import ngettext from hashlib import md5 from typing import Set -import cairo from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import GES from gi.repository import Gio from gi.repository import GLib from gi.repository import GObject +from gi.repository import Graphene from gi.repository import Gst from gi.repository import GstPbutils from gi.repository import Gtk @@ -1693,37 +1693,38 @@ class MediaLibraryWidget(Gtk.Box, Loggable): return True def _flowbox_prepare_cb(self, drag_source, unused_x, unused_y): + self.dragged = True + self._dragged_paths = self.get_selected_paths() + + if not self._dragged_paths: + drag_source.drag_cancel() + uris = [Gio.File.new_for_uri(self.store[path].uri) for path in self._dragged_paths] file_list = Gdk.FileList.new_from_list(uris) - value = GLib.Value() - value.init(Gdk.FileList) - value.set_value(file_list) + value = GObject.Value(Gdk.FileList, file_list) content_provider = Gdk.ContentProvider.new_for_value(value) drag_source.set_content(content_provider) return content_provider def _flowbox_drag_begin_cb(self, drag_source, drag): - self.dragged = True - self._dragged_paths = self.get_selected_paths() + row = self.store[self._dragged_paths[0]] + icon = row.icon_128 - if not self._dragged_paths: - drag_source.drag_cancel() - else: - row = self.store[self._dragged_paths[0]] - icon = row.icon_128 + icon_height = icon.get_height() + icon_width = icon.get_width() + + snapshot = Gtk.Snapshot.new() + bounds = Graphene.Rect().init(0, 0, 2 * icon_width, 2 * icon_height) + ctx = snapshot.append_cairo(bounds) - icon_height = icon.get_height() - icon_width = icon.get_width() + ctx.translate(icon_width / 2, icon_height / 2) - paintable = Gdk.Paintable.new_empty(icon_width, icon_height) - ctx = cairo.Context(paintable) - # Center the icon around the cursor. - ctx.translate(icon_width / 2, icon_height / 2) + Gdk.cairo_set_source_pixbuf(ctx, icon, 0, 0) + ctx.paint_with_alpha(0.35) - Gdk.cairo_set_source_pixbuf(ctx, icon, 0, 0) - ctx.paint_with_alpha(0.35) + paintable = snapshot.to_paintable(Graphene.Size().init(2 * icon_width, 2 * icon_height)) - drag_source.set_icon(paintable, icon_width, icon_height) + drag_source.set_icon(paintable, icon_width, icon_height) def _flowbox_drag_end_cb(self, drag_source, drag, delete_data): self.info("Drag operation ended") diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index e7d962ed3..0cf56b088 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -243,6 +243,7 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): Loggable.__init__(self) self.fixed = Gtk.Fixed() + self.set_child(self.fixed) self._timeline = timeline self.snap_position = 0 @@ -504,10 +505,11 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.__last_clips_on_leave = None # To be able to receive effects dragged on clips. - drop_target = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) - drop_target.set_gtypes([GObject.TYPE_STRING, Gdk.FileList]) - mini_layout_controller = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) - mini_layout_controller.set_gtypes([GObject.TYPE_STRING, Gdk.FileList]) + drop_target = Gtk.DropTarget.new(GObject.TYPE_NONE, Gdk.DragAction.COPY) + drop_target.set_preload(True) + drop_target.set_gtypes([Gdk.FileList, GObject.TYPE_STRING]) + mini_layout_controller = Gtk.DropTarget.new(GObject.TYPE_NONE, Gdk.DragAction.COPY) + mini_layout_controller.set_gtypes([Gdk.FileList, GObject.TYPE_STRING]) drop_target.connect("accept", self._accept_cb) drop_target.connect("notify", self._notify_cb) @@ -518,7 +520,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): mini = True mini_layout_controller.connect("accept", self._accept_cb) - mini_layout_controller.connect("notify", self._notify_cb) + mini_layout_controller.connect("notify::preload", self._notify_cb) mini_layout_controller.connect("motion", self._motion_cb, self.mini_layout_container, mini) mini_layout_controller.connect("leave", self._leave_cb) mini_layout_controller.connect("drop", self._drop_cb) @@ -1166,35 +1168,35 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.dragging_group = self.selection.group() def _accept_cb(self, drop_target, drop): - drop_target.set_preload(True) return True def _notify_cb(self, drop_target, pspec): - data = drop_target.get_value() - data_type = data.get_gtype() - if not self.drop_data_ready: + data = drop_target.props.value + if not self.drop_data_ready and data is not None: self.__last_clips_on_leave = None - if data_type == GObject.TYPE_STRING: + if isinstance(data, str): # Dragging an effect from the Effect Library. - factory_name = data.get_string() + factory_name = str(data) self.drop_data = factory_name self.drop_data_ready = True - elif data_type == Gdk.FileList: + elif isinstance(data, Gdk.FileList): self.drop_data = [file.get_uri() for file in data.get_files()] self.drop_data_ready = True def _motion_cb(self, drop_target, x, y, widget, mini=False): - drop = drop_target.get_drop() - data_type = drop_target.get_value().get_gtype() - if self.drop_data_ready and data_type == Gdk.FileList: + data = drop_target.get_value() + if self.drop_data_ready and isinstance(data, Gdk.FileList): layers_box = self.layout.layers_vbox if not mini else self.mini_layout.layers_vbox x, y = widget.translate_coordinates(layers_box, x, y) + # print(temp) + # x = 10 + # y = 10 if not self.dropping_clips: # The preview clips have not been created yet. self.__create_clips(x, y, mini) self.__drag_update(x, y, mini) - drop.status(drop.get_actions(), Gdk.DragAction.COPY) + # # drop.status(drop.get_actions(), Gdk.DragAction.COPY) return drop_target.get_actions() def _leave_cb(self, drop_target): @@ -1202,7 +1204,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): # See how __on_separators is used in __dragDropCb for details self._set_separators_prelight(False) - data_type = drop_target.get_value().get_gtype() + data = drop_target.get_value() if self.dragging_element: self.__last_clips_on_leave = [(clip.get_layer(), clip) for clip in self.dragging_group.get_children(False)] @@ -1219,7 +1221,7 @@ class Timeline(Gtk.Box, Zoomable, Loggable): self.dropping_clips = False self.dragging_group.ungroup(recursive=False) self.dragging_group = None - elif data_type == Gdk.FileList: + elif isinstance(data, Gdk.FileList): self.clean_drop_data() def clean_drop_data(self): @@ -1232,10 +1234,9 @@ class Timeline(Gtk.Box, Zoomable, Loggable): # it zoom_was_fitted = self.zoomed_fitted - data_type = value.get_gtype() success = True self.clean_drop_data() - if data_type == Gdk.FileList: + if isinstance(value, Gdk.FileList): if self.__last_clips_on_leave: pipeline = self._project.pipeline with self.app.action_log.started("add clip", diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 207f7f1d0..842115a6a 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -291,7 +291,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.peak_meter_scale.set_margin_start(SPACING) self.peak_meter_box.append(self.peak_meter_scale) self.viewer_row_box.append(self.peak_meter_box) - self.peak_meter_scale.connect("notify::content_height", self.__peak_meter_scale_notify_content_height_cb) + self.peak_meter_scale.connect("notify", self.__peak_meter_scale_notify_content_height_cb) # Buttons/Controls bbox = Gtk.Box() @@ -765,17 +765,23 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): self.snaps.append(1 / divisor) self.snaps += list(range(1, 10)) - def do_get_preferred_width(self): - minimum, unused_natural = Gtk.AspectFrame.do_get_preferred_width(self) - # Do not let a chance for Gtk to choose video natural size - # as we want to have full control - return minimum, minimum + 1 + # def do_get_preferred_width(self): + # minimum, unused_natural = Gtk.AspectFrame.do_get_preferred_width(self) + # # Do not let a chance for Gtk to choose video natural size + # # as we want to have full control + # return minimum, minimum + 1 + + # def do_get_preferred_height(self): + # minimum, unused_natural = Gtk.AspectFrame.do_get_preferred_height(self) + # # Do not let a chance for Gtk to choose video natural size + # # as we want to have full control + # return minimum, minimum + 1 - def do_get_preferred_height(self): - minimum, unused_natural = Gtk.AspectFrame.do_get_preferred_height(self) + def do_measure(self, orientation, for_size): + minimum, unused_natural = Gtk.AspectFrame.do_measure(self, orientation, for_size) # Do not let a chance for Gtk to choose video natural size # as we want to have full control - return minimum, minimum + 1 + return minimum, minimum + 1, -1, -1 def do_compute_child_allocation(self, allocation): """Snaps the size of the child depending on the project size.""" -- GitLab From 0e94a0c808ed8df61a4eadf6f44b12c70d028673 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Wed, 28 Jun 2023 17:31:00 +0530 Subject: [PATCH 122/132] GtkContainer: replace deprecated propagate_draw() --- pitivi/timeline/elements.py | 10 ++++------ pitivi/timeline/layer.py | 6 ++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 35f9effbc..1dfb02143 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -806,21 +806,19 @@ class TimelineElement(Gtk.Fixed, Zoomable, Loggable): def do_snapshot(self, snapshot): Gtk.Fixed.do_snapshot(self, snapshot) - bounds = Graphene.Rect().init(0, 0, self.__width, self.__height) - cr = snapshot.append_cairo(bounds) - self.propagate_draw(self.__background, cr) + self.snapshot_child(self.__background, snapshot) if self.previewer: - self.propagate_draw(self.previewer, cr) + self.snapshot_child(self.previewer, snapshot) if self.keyframe_curve and self.keyframe_curve.is_drawable(): project = self.timeline.app.project_manager.current_project if project.pipeline.get_simple_state() != Gst.State.PLAYING: - self.propagate_draw(self.keyframe_curve, cr) + self.snapshot_child(self.keyframe_curve, snapshot) if self.markers and self.markers.is_drawable(): - self.propagate_draw(self.markers, cr) + self.snapshot_child(self.markers, snapshot) # Callbacks def __selected_changed_cb(self, unused_selected, selected): diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index 6eba691be..dc3a5b8a1 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -20,7 +20,6 @@ from gettext import gettext as _ from gi.repository import Gdk from gi.repository import GES from gi.repository import Gio -from gi.repository import Graphene from gi.repository import Gtk from pitivi.timeline import elements @@ -409,8 +408,7 @@ class Layer(Gtk.Fixed, Loggable): def do_snapshot(self, snapshot): Gtk.Fixed.do_snapshot(self, snapshot) - bounds = Graphene.Rect().init(0, 0, self.get_width(), self.get_height()) - cr = snapshot.append_cairo(bounds) + if self._changed: self._children.sort(key=lambda clip: clip.z_order) for child in self._children: @@ -420,7 +418,7 @@ class Layer(Gtk.Fixed, Loggable): self._changed = False for child in self._children: - self.propagate_draw(child, cr) + self.snapshot_child(child, snapshot) class FullLayer(Layer, Zoomable): -- GitLab From 0272822e7f8c0582c962a10aee177035d0c28ade Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Wed, 28 Jun 2023 19:34:48 +0530 Subject: [PATCH 123/132] GtkModelButton: adapt to new popover menu --- data/ui/mainmenubutton.ui | 234 ++++++++-------------------- pitivi/clip_properties/alignment.py | 4 +- pitivi/editorperspective.py | 2 + pitivi/greeterperspective.py | 11 +- pitivi/interactiveintro.py | 16 +- pitivi/timeline/elements.py | 40 ++--- pitivi/timeline/previewers.py | 10 +- plugins/console/console.py | 4 +- 8 files changed, 110 insertions(+), 211 deletions(-) diff --git a/data/ui/mainmenubutton.ui b/data/ui/mainmenubutton.ui index 55aebf91e..f6c2b28b2 100644 --- a/data/ui/mainmenubutton.ui +++ b/data/ui/mainmenubutton.ui @@ -2,178 +2,76 @@ - - False - - - True - False - 12 - 12 - 8 - 8 - vertical - - - True - True - False - Save the current project under a new name or a different location - 1 - 1 - editor.save-as - fill - Save As... - - - - - True - True - False - Reload the current project - 1 - 1 - editor.revert-to-saved - fill - Revert to saved version - - - - - True - True - False - Export the current project and all its media in a .tar archive - 1 - 1 - editor.export-project - fill - Export as Archive... - - - - - True - False - 2 - 2 - fill - - - - - True - True - False - Export the frame at the current playhead position as an image file. - 1 - 1 - editor.save-frame - fill - Export current frame... - - - - - True - False - 2 - 2 - fill - - - - - True - True - False - Edit the project settings - 1 - 1 - editor.project-settings - fill - Project Settings - - - - - True - False - 2 - 2 - fill - - - - - True - True - False - 1 - 1 - win.preferences - Preferences - fill - - - - - True - True - False - 1 - 1 - app.shortcuts_window - fill - Keyboard Shortcuts - - - - - True - True - False - 1 - 1 - win.help - fill - User Manual - - - - - True - True - False - Start the intro to Pitivi for new users - 1 - 1 - editor.interactive-intro - fill - Interactive Intro - - - - - True - True - False - 1 - 1 - win.about - fill - About Pitivi - - - - - + +
+ + Save As... + editor.save-as + + + Revert to saved version + editor.revert-to-saved + + + Export as Archive... + editor.export-project + +
+
+ + Export current frame... + editor.save-frame + +
+
+ + Project Settings + editor.project-settings + +
+
+ + Preferences + win.preferences + + + Keyboard Shortcuts + app.shortcuts_window + + + User Manual + win.help + + + Interactive Intro + editor.interactive-intro + + + About Pitivi + win.about + +
+
+ +
+ + Keyboard Shortcuts + app.shortcuts_window + + + User Manual + win.help + + + About Pitivi + win.about + +
+
True True True - menu open-menu-symbolic
diff --git a/pitivi/clip_properties/alignment.py b/pitivi/clip_properties/alignment.py index 7eaca297b..ed07477c5 100644 --- a/pitivi/clip_properties/alignment.py +++ b/pitivi/clip_properties/alignment.py @@ -124,7 +124,7 @@ class AlignmentEditor(Gtk.Box, Loggable): y = height / 8 * self._hovered_box[1] cr.rectangle(x, y, box_width, box_height) - color = self.get_color(Gtk.StateFlags.LINK) + color = self.get_style_context().get_color() cr.set_source_rgba(color.red, color.green, color.blue, 0.7) cr.set_line_width(1) cr.fill() @@ -147,7 +147,7 @@ class AlignmentEditor(Gtk.Box, Loggable): cr.move_to(width - line_offset_x, 0) cr.line_to(width - line_offset_x, height) - color = self.get_color(Gtk.StateFlags.ACTIVE) + color = self.get_style_context().get_color() cr.set_source_rgba(color.red, color.green, color.blue, 0.6) cr.set_line_width(1) cr.stroke() diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 3cfc1f07e..562eabcd2 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -353,6 +353,8 @@ class EditorPerspective(Perspective, Loggable): os.path.join(get_ui_dir(), "mainmenubutton.ui")) self.menu_button = self.builder.get_object("menubutton") + menu_model = self.builder.get_object("editor_menu_model") + self.menu_button.set_menu_model(menu_model) self.keyboard_shortcuts_button = self.builder.get_object("menu_shortcuts") headerbar.pack_end(self.menu_button) diff --git a/pitivi/greeterperspective.py b/pitivi/greeterperspective.py index 86ea29961..b83c711ce 100644 --- a/pitivi/greeterperspective.py +++ b/pitivi/greeterperspective.py @@ -311,15 +311,8 @@ class GreeterPerspective(Perspective): builder.add_from_file(os.path.join(get_ui_dir(), "mainmenubutton.ui")) menu_button = builder.get_object("menubutton") # Menu options we want to display. - visible_options = ["menu_shortcuts", "menu_help", "menu_about"] - widget = builder.get_object("menu_box").get_first_child() - while widget: - if Gtk.Buildable.get_buildable_id(widget) not in visible_options: - widget.hide() - else: - visible_options.remove(Gtk.Buildable.get_buildable_id(widget)) - widget = widget.get_next_sibling() - assert not visible_options + menu_model = builder.get_object("greeter_menu_model") + menu_button.set_menu_model(menu_model) return menu_button def _drop_cb(self, drop_target, value, x, y): diff --git a/pitivi/interactiveintro.py b/pitivi/interactiveintro.py index 3a3913e0b..2e3860aa2 100644 --- a/pitivi/interactiveintro.py +++ b/pitivi/interactiveintro.py @@ -38,11 +38,6 @@ INTERACTIVE_INTRO_CSS = """ margin: 10px; } - -#intro-popover { - background-color: @theme_selected_bg_color; -} - #intro-popover > box { margin: 10px; } @@ -189,10 +184,11 @@ class InteractiveIntro(GObject.Object): self.widget = widget self.widget.add_css_class("intro-highlight") - if isinstance(self.widget, Gtk.ModelButton): - self.parent_widget = self._find_parent(self.widget, Gtk.Popover) - if self.parent_widget: - self.parent_widget.popup() + if isinstance(self.widget, Gtk.Button): + if self.widget == self.app.gui.editor.keyboard_shortcuts_button: + self.parent_widget = self._find_parent(self.widget, Gtk.Popover) + if self.parent_widget: + self.parent_widget.popup() def _find_parent(self, widget, parent_class): while widget: @@ -251,7 +247,7 @@ class InteractiveIntro(GObject.Object): self.set_current_widget(widget) popover = self.__create_popover(text) - popover.set_relative_to(widget) + popover.set_parent(widget) if center: rect = Gdk.Rectangle() diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 1dfb02143..480ddad79 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -174,16 +174,14 @@ class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): eventcontroller_click = Gtk.GestureClick() eventcontroller_motion = Gtk.EventControllerMotion() - eventcontroller_legacy = Gtk.EventControllerLegacy() eventcontroller_motion.connect("motion", self.__motion_notify_event_cb) - eventcontroller_legacy.connect("event", self._event_cb) + eventcontroller_motion.connect("leave", self._leave_notify_event_cb) self.connect("notify::height-request", self.__height_request_cb) eventcontroller_click.connect("released", self._button_release_event_cb) eventcontroller_click.set_button(1) self.add_controller(eventcontroller_click) self.add_controller(eventcontroller_motion) - self.add_controller(eventcontroller_legacy) self.mpl_connect('button_press_event', self._mpl_button_press_event_cb) self.mpl_connect('button_release_event', self._mpl_button_release_event_cb) @@ -290,11 +288,9 @@ class KeyframeCurve(FigureCanvasGTK4Cairo, Loggable): return True return False - def _event_cb(self, controller, event): - if event.type == Gdk.EventType.LEAVE_NOTIFY: - cursor = NORMAL_CURSOR - self._timeline.set_cursor(cursor) - return False + def _leave_notify_event_cb(self, controller): + cursor = NORMAL_CURSOR + self._timeline.set_cursor(cursor) def _mpl_button_press_event_cb(self, event): if event.button != MouseButton.LEFT: @@ -1161,7 +1157,7 @@ class TrimHandle(Gtk.Box, Loggable): cr = snapshot.append_cairo(bounds) if TrimHandle.PIXBUF is None: - TrimHandle.PIXBUF = GdkPixbuf.PixBuf.new_from_file( + TrimHandle.PIXBUF = GdkPixbuf.Pixbuf.new_from_file( os.path.join(get_pixmap_dir(), "trimbar-focused.png")) Gdk.cairo_set_source_pixbuf(cr, TrimHandle.PIXBUF, 10, 10) @@ -1213,12 +1209,13 @@ class Clip(Gtk.Box, Loggable): # Connect to Widget signals. eventcontroller_click = Gtk.GestureClick() - eventcontroller_legacy = Gtk.EventControllerLegacy() + eventcontroller_motion = Gtk.EventControllerMotion() eventcontroller_click.connect("released", self._button_release_event_cb) - eventcontroller_legacy.connect("event", self._event_cb) + eventcontroller_motion.connect("enter", self._eventcontroller_motion_enter_cb) + eventcontroller_motion.connect("leave", self._eventcontroller_motion_leave_cb) self.add_controller(eventcontroller_click) - self.add_controller(eventcontroller_legacy) + self.add_controller(eventcontroller_motion) # Connect to GES signals. self.ges_clip.connect("notify::start", self._start_changed_cb) @@ -1364,16 +1361,23 @@ class Clip(Gtk.Box, Loggable): for handle in self.handles: handle.hide() - def _event_cb(self, controller, event): + def _eventcontroller_motion_enter_cb(self, controller, unused_x, unused_y): prelight = None - if (event.type == Gdk.EventType.ENTER_NOTIFY and - event.mode == Gdk.CrossingMode.NORMAL and + event = controller.get_current_event() + if(event is not None and event.get_mode() == Gdk.CrossingMode.NORMAL and not self.timeline.scrubbing): + print("enter_notify_event_cb") prelight = True for handle in self.handles: handle.enlarge() - elif (event.type == Gdk.EventType.LEAVE_NOTIFY and - event.mode == Gdk.CrossingMode.NORMAL): + + if prelight is not None: + set_state_flags_recurse(self, Gtk.StateFlags.PRELIGHT, are_set=prelight, ignored_classes=(Marker,)) + + def _eventcontroller_motion_leave_cb(self, controller): + prelight = None + event = controller.get_current_event() + if event is not None and event.get_mode() == Gdk.CrossingMode.NORMAL: prelight = False for handle in self.handles: handle.shrink() @@ -1381,8 +1385,6 @@ class Clip(Gtk.Box, Loggable): if prelight is not None: set_state_flags_recurse(self, Gtk.StateFlags.PRELIGHT, are_set=prelight, ignored_classes=(Marker,)) - return False - def _start_changed_cb(self, clip, pspec): self.update_position() diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py index bd0edd1db..4c36c738a 100644 --- a/pitivi/timeline/previewers.py +++ b/pitivi/timeline/previewers.py @@ -1308,7 +1308,15 @@ class AudioPreviewer(Gtk.Fixed, Previewer, Zoomable, Loggable): # The area we have to refresh is this rect inside the clip. # For example rect.x is > 0 when the start of the clip is out of view. # rect.width = how many pixels of the clip are in view horizontally. - res, rect = Gdk.cairo_get_clip_rectangle(context) + + x1, y1, x2, y2 = context.clip_extents() + rect = Gdk.Rectangle() + rect.x = x1 + rect.y = y1 + rect.width = x2 - x1 + rect.height = y2 - y1 + + res = (rect.width > 0 and rect.height > 0) assert res start = self.ges_elem.props.start diff --git a/plugins/console/console.py b/plugins/console/console.py index d6e8977cc..6933bd7c5 100644 --- a/plugins/console/console.py +++ b/plugins/console/console.py @@ -160,8 +160,8 @@ class Console(GObject.GObject, Peas.Activatable): def add_menu_item(self): """Inserts a menu item into the Pitivi menu.""" menu = self.app.gui.editor.builder.get_object("menu_box") - self.menu_item = Gtk.ModelButton.new() - self.menu_item.props.text = _("Developer Console") + self.menu_item = Gtk.Button.new() + self.menu_item.props.label = _("Developer Console") self.menu_item.set_action_name("app.open_console") menu.append(self.menu_item) -- GitLab From 02a18ad163919df2c22eaab96a83e9341d4b9e81 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 4 Jul 2023 17:01:32 +0530 Subject: [PATCH 124/132] GtkSink: update manifest to add new gst-rs-plugins --- build/flatpak/org.pitivi.Pitivi.json | 39 ++++++++++++++++++++++++++++ build/flatpak/pitivi-flatpak | 3 +++ 2 files changed, 42 insertions(+) diff --git a/build/flatpak/org.pitivi.Pitivi.json b/build/flatpak/org.pitivi.Pitivi.json index f1b33c7a7..f8348046a 100644 --- a/build/flatpak/org.pitivi.Pitivi.json +++ b/build/flatpak/org.pitivi.Pitivi.json @@ -19,8 +19,13 @@ ], "sdk": "org.gnome.Sdk", "copy-icon": true, + "sdk-extensions": [ + "org.freedesktop.Sdk.Extension.rust-stable" + ], "build-options": { + "append-path": "/usr/lib/sdk/rust-stable/bin", "env": { + "CARGO_HOME": "/run/build/cargo-c/cargo", "PYTHON": "python3", "GST_PLUGIN_SYSTEM_PATH": "/app/lib/gstreamer-1.0/", "FREI0R_PATH": "/app/lib/frei0r-1/" @@ -419,6 +424,40 @@ } ] }, + { + "name": "cargo-c", + "buildsystem": "simple", + "build-commands": [ + "cargo install cargo-c --root /app" + ], + "build-options": { + "build-args": [ + "--share=network" + ] + }, + "cleanup": [ + "*" + ] + }, + { + "name": "gst-plugins-rs", + "buildsystem": "simple", + "sources": [ + { + "type": "git", + "url": "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs", + "branch": "0.10" + } + ], + "build-options": { + "build-args": [ + "--share=network" + ] + }, + "build-commands": [ + "cargo cinstall -p gst-plugin-gtk4 --prefix=/app" + ] + }, { "name": "pitivi", "buildsystem": "meson", diff --git a/build/flatpak/pitivi-flatpak b/build/flatpak/pitivi-flatpak index e27aa7ad8..f0f4fa378 100755 --- a/build/flatpak/pitivi-flatpak +++ b/build/flatpak/pitivi-flatpak @@ -120,6 +120,9 @@ def expand_manifest(manifest_path, outfile, basedir, gst_version, branchname): # This is the name of a file to be included containing modules. continue + if "sources" not in module: + continue + if module["sources"][0]["type"] != "git": continue -- GitLab From d850cc1edf3a9e59bc5956a70a7d9f1fb3cb0b65 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 4 Jul 2023 19:27:37 +0530 Subject: [PATCH 125/132] ViewerWidget: replace AspectFrame with Gtk.Frame --- pitivi/viewer/viewer.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index 842115a6a..bc4606f4e 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -195,6 +195,8 @@ class ViewerContainer(Gtk.Box, Loggable): self.external_vbox.prepend(self.viewer_row_box) self.external_vbox.child_set(self.viewer_row_box, fill=True) + self.target.show() + # Wait for 1s to make sure that the viewer has completely realized # and then we can mark the resize status as showable. GLib.timeout_add(1000, self.__viewer_realization_done_cb, None) @@ -719,7 +721,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.app.simple_uninhibit(ViewerContainer.INHIBIT_REASON) -class ViewerWidget(Gtk.AspectFrame, Loggable): +class ViewerWidget(Gtk.Frame, Loggable): """Container responsible with enforcing the aspect ratio. Args: @@ -728,12 +730,13 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): """ def __init__(self, video_widget): - Gtk.AspectFrame.__init__(self, xalign=0.5, yalign=0.5, ratio=4 / 3, obey_child=False) + Gtk.Frame.__init__(self) Loggable.__init__(self) # The width and height used when snapping the child widget size. self.videowidth = 0 self.videoheight = 0 + self.ratio = 4 / 3 # Sequence of floats representing sizes where the viewer size snaps. # The project natural video size is 1, double size is 2, etc. self.snaps = [] @@ -745,16 +748,16 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): self.hide() def switch_widget(self, widget): - child = self.get_child() - if child: - self.remove(child) + # child = self.get_child() + # if child: + # self.remove(child) self.set_child(widget) def update_aspect_ratio(self, project): """Forces the DAR of the project on the child widget.""" ratio_fraction = project.get_dar() self.debug("Updating aspect ratio to %r", ratio_fraction) - self.props.ratio = float(ratio_fraction) + self.ratio = float(ratio_fraction) self.videowidth = project.videowidth self.videoheight = project.videoheight @@ -765,20 +768,8 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): self.snaps.append(1 / divisor) self.snaps += list(range(1, 10)) - # def do_get_preferred_width(self): - # minimum, unused_natural = Gtk.AspectFrame.do_get_preferred_width(self) - # # Do not let a chance for Gtk to choose video natural size - # # as we want to have full control - # return minimum, minimum + 1 - - # def do_get_preferred_height(self): - # minimum, unused_natural = Gtk.AspectFrame.do_get_preferred_height(self) - # # Do not let a chance for Gtk to choose video natural size - # # as we want to have full control - # return minimum, minimum + 1 - def do_measure(self, orientation, for_size): - minimum, unused_natural = Gtk.AspectFrame.do_measure(self, orientation, for_size) + minimum, unused_natural, unused_minimum_baseline, unused_natural_baseline = Gtk.Widget.do_measure(self, orientation, for_size) # Do not let a chance for Gtk to choose video natural size # as we want to have full control return minimum, minimum + 1, -1, -1 @@ -786,7 +777,7 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): def do_compute_child_allocation(self, allocation): """Snaps the size of the child depending on the project size.""" # Start with the max possible allocation. - Gtk.AspectFrame.do_compute_child_allocation(self, allocation) + Gtk.Frame.do_compute_child_allocation(self, allocation) if not self.videowidth: return @@ -810,8 +801,10 @@ class ViewerWidget(Gtk.AspectFrame, Loggable): allocation.width = self.videowidth * snap allocation.height = self.videoheight * snap full = self.get_allocation() - allocation.x = full.x + self.props.xalign * (full.width - allocation.width) - allocation.y = full.y + self.props.yalign * (full.height - allocation.height) + xalign = 0.5 + yalign = 0.5 + allocation.x = full.x + xalign * (full.width - allocation.width) + allocation.y = full.y + yalign * (full.height - allocation.height) class PlayPauseButton(Gtk.Button, Loggable): -- GitLab From e05d0dec1ff5709ebae14938bcdf2198acfd5691 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Fri, 7 Jul 2023 18:28:35 +0530 Subject: [PATCH 126/132] ClipProperties: adapt to Gtk4 --- data/ui/clipcompositing.ui | 4 +++ pitivi/clip_properties/compositing.py | 2 ++ pitivi/clip_properties/markers.py | 17 +++++------ pitivi/clipproperties.py | 44 +++++++++++++-------------- pitivi/effects.py | 2 ++ pitivi/medialibrary.py | 2 +- pitivi/timeline/elements.py | 3 +- pitivi/utils/widgets.py | 2 +- 8 files changed, 42 insertions(+), 34 deletions(-) diff --git a/data/ui/clipcompositing.ui b/data/ui/clipcompositing.ui index 01441f76a..abc409787 100644 --- a/data/ui/clipcompositing.ui +++ b/data/ui/clipcompositing.ui @@ -162,6 +162,10 @@ start + + 1 + 2 + diff --git a/pitivi/clip_properties/compositing.py b/pitivi/clip_properties/compositing.py index e2aec4f67..ba5ae77ed 100644 --- a/pitivi/clip_properties/compositing.py +++ b/pitivi/clip_properties/compositing.py @@ -62,6 +62,8 @@ class CompositingProperties(Gtk.Expander, Loggable): compositing_box = builder.get_object("compositing_box") self._fade_in_adjustment = builder.get_object("fade_in_adjustment") self._fade_out_adjustment = builder.get_object("fade_out_adjustment") + self.textbox = builder.get_object("blending_mode") + self.textbox.connect("changed", self._blending_property_changed_cb) self._video_source: Optional[GES.VideoSource] = None self._control_source: Optional[Gst.ControlSource] = None diff --git a/pitivi/clip_properties/markers.py b/pitivi/clip_properties/markers.py index 9a40770f1..9da49c5d0 100644 --- a/pitivi/clip_properties/markers.py +++ b/pitivi/clip_properties/markers.py @@ -104,7 +104,7 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): child_type = child.get_track_type() name = ClipMarkersProperties.TRACK_TYPES[child_type] label = Gtk.Label.new(name) - row_box.prepend(label) + row_box.append(label) label.show() labels_size_group.add_widget(label) row_size_group.add_widget(label) @@ -119,28 +119,27 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): list_store = Gtk.ListStore(str, str) list_combo = Gtk.ComboBox.new_with_model(list_store) renderer_text = Gtk.CellRendererText() - renderer_text.set_hexpand(True) - list_combo.prepend(renderer_text) + # list_combo.append(renderer_text) # TODO: porting: adapt to new method list_combo.add_attribute(renderer_text, "text", 1) list_combo.set_id_column(0) - selection_box.prepend(list_combo) + selection_box.append(list_combo) list_combo.show() combos_size_group.add_widget(list_combo) row_size_group.add_widget(list_combo) snap_toggle = Gtk.CheckButton.new_with_label(_("Magnetic")) - selection_box.prepend(snap_toggle) + selection_box.append(snap_toggle) if GES_MARKERS_SNAPPABLE: snap_toggle.show() - controls_box.prepend(selection_box) + controls_box.append(selection_box) if isinstance(child, GES.AudioSource) and "librosa" not in MISSING_SOFT_DEPS: container = self._create_beat_detection_ui() - controls_box.prepend(container) + controls_box.append(container) audio_source = child - row_box.prepend(controls_box) + row_box.append(controls_box) manager = child.markers_manager list_combo.connect("changed", self._combo_changed_cb, child, snap_toggle) @@ -157,7 +156,7 @@ class ClipMarkersProperties(Gtk.Expander, Loggable): if child_type == GES.TrackType.AUDIO: self.expander_box.append(row_box) else: - self.expander_box.prepend(row_box) + self.expander_box.append(row_box) self._set_audio_source(audio_source) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index fcfbf76a0..9d33335b6 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -106,39 +106,39 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): self.clips_box = Gtk.Box() self.clips_box.set_orientation(Gtk.Orientation.VERTICAL) self.clips_box.show() - vbox.prepend(self.clips_box) + vbox.append(self.clips_box) self.transformation_expander = TransformationProperties(app) self.transformation_expander.set_vexpand(False) - vbox.prepend(self.transformation_expander) + vbox.append(self.transformation_expander) self.speed_expander = TimeProperties(app) self.speed_expander.set_vexpand(False) if in_devel(): - vbox.prepend(self.speed_expander) + vbox.append(self.speed_expander) self.title_expander = TitleProperties(app) self.title_expander.set_vexpand(False) - vbox.prepend(self.title_expander) + vbox.append(self.title_expander) self.color_expander = ColorProperties(app) self.color_expander.set_vexpand(False) - vbox.prepend(self.color_expander) + vbox.append(self.color_expander) self.compositing_expander = CompositingProperties(app) self.compositing_expander.set_vexpand(False) - vbox.prepend(self.compositing_expander) + vbox.append(self.compositing_expander) self.effect_expander = EffectProperties(app) self.effect_expander.set_vexpand(False) - vbox.prepend(self.effect_expander) + vbox.append(self.effect_expander) self.marker_expander = ClipMarkersProperties(app) self.marker_expander.set_vexpand(False) - vbox.prepend(self.marker_expander) + vbox.append(self.marker_expander) self.helper_box = self.create_helper_box() - self.clips_box.prepend(self.helper_box) + self.clips_box.append(self.helper_box) disable_scroll(vbox) @@ -338,8 +338,8 @@ class TimeProperties(Gtk.Expander, Loggable): hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - hbox.prepend(self._speed_spin_button) - hbox.prepend(self._speed_scale) + hbox.append(self._speed_spin_button) + hbox.append(self._speed_scale) self.__add_widget_to_grid(grid, _("Speed"), hbox, self._speed_reset_button_clicked_cb, 0) self.__setting_rate = False @@ -642,13 +642,13 @@ class EffectProperties(Gtk.Expander, Loggable): self.cover_object_button = Gtk.MenuButton() self.cover_object_button.set_label(_("Cover Object")) self.cover_object_button.set_direction(Gtk.ArrowType.NONE) - self.object_tracker_box.prepend(self.cover_object_button) + self.object_tracker_box.append(self.cover_object_button) drop_target = Gtk.DropTarget.new(GObject.TYPE_STRING, Gdk.DragAction.COPY) - self.expander_box.prepend(self.effects_listbox) - self.expander_box.prepend(self.add_effect_button) - self.expander_box.prepend(self.object_tracker_box) + self.expander_box.append(self.effects_listbox) + self.expander_box.append(self.add_effect_button) + self.expander_box.append(self.object_tracker_box) self.set_child(self.expander_box) @@ -701,7 +701,7 @@ class EffectProperties(Gtk.Expander, Loggable): expander.connect("notify::expanded", self._toggle_expander_cb, config_ui_revealer) remove_effect_button = Gtk.Button.new_from_icon_name("window-close") - remove_effect_button.props.margin_end = PADDING + remove_effect_button.props.margin_start = PADDING row_widgets_box = Gtk.Box() row_drag_icon = Gtk.Picture.new_for_pixbuf(self.drag_lines_pixbuf) @@ -710,13 +710,13 @@ class EffectProperties(Gtk.Expander, Loggable): row_drag_icon.props.margin_start = PADDING row_drag_icon.props.margin_end = PADDING - row_widgets_box.prepend(row_drag_icon) - row_widgets_box.prepend(toggle) - row_widgets_box.prepend(expander) + row_widgets_box.append(row_drag_icon) + row_widgets_box.append(toggle) + row_widgets_box.append(expander) row_widgets_box.append(remove_effect_button) - vbox.prepend(row_widgets_box) - vbox.prepend(config_ui_revealer) + vbox.append(row_widgets_box) + vbox.append(config_ui_revealer) event_box = Gtk.Box() event_box.append(vbox) @@ -998,7 +998,7 @@ class TransformationProperties(Gtk.Expander, Loggable): self.alignment_editor.connect("align", self.__alignment_editor_align_cb) self.alignment_editor.set_hexpand(True) self.alignment_editor.set_halign(Gtk.Align.FILL) - alignment_editor_container.prepend(self.alignment_editor) + alignment_editor_container.append(self.alignment_editor) self.__control_bindings = {} # Used to make sure self.__control_bindings_changed doesn't get called diff --git a/pitivi/effects.py b/pitivi/effects.py index e6441e7a4..b456991ec 100644 --- a/pitivi/effects.py +++ b/pitivi/effects.py @@ -335,6 +335,8 @@ class EffectsManager(Loggable): else: bin_description = effect + if isinstance(bin_description, list): + bin_description = bin_description[0] name = EffectInfo.name_from_bin_description(bin_description) return self._effects.get(name) diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py index 7038292ab..1df16e6a0 100644 --- a/pitivi/medialibrary.py +++ b/pitivi/medialibrary.py @@ -1558,7 +1558,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable): selected_count = len(self.flowbox.get_selected_children()) self.remove_assets_action.set_enabled(selected_count) self.insert_at_end_action.set_enabled(selected_count) - self.tags_button.set_sensitive(selected_count) + self.tags_button.set_sensitive(selected_count == 1) # Some actions can only be done on a single item at a time: self._clipprops_button.set_sensitive(selected_count == 1) diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py index 480ddad79..c4633281e 100644 --- a/pitivi/timeline/elements.py +++ b/pitivi/timeline/elements.py @@ -1243,7 +1243,8 @@ class Clip(Gtk.Box, Loggable): with self.app.action_log.started("add effect", finalizing_action=CommitTimelineFinalizingAction(pipeline), toplevel=True): - self.add_effect(effect_info) + if effect_info: + self.add_effect(effect_info) self.timeline.clean_drop_data() success = True diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py index 0777f78bd..a4302046a 100644 --- a/pitivi/utils/widgets.py +++ b/pitivi/utils/widgets.py @@ -980,7 +980,7 @@ class GstElementSettingsWidget(Gtk.Box, Loggable): def __create_reset_to_default_button(self, unused_prop, widget, keyframe_button): icon = Gtk.Image() - icon.set_from_icon_name("edit-clear-all-symbolic", Gtk.IconSize.NORMAL) + icon.set_from_icon_name("edit-clear-all-symbolic") button = Gtk.Button() button.set_child(icon) button.set_tooltip_text(_("Reset to default value")) -- GitLab From c9946cc108cbfc4a32f316961f936b31e8c2ef45 Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Tue, 1 Aug 2023 21:36:49 +0530 Subject: [PATCH 127/132] Gtk4-Port: fix timeline --- pitivi/mediafilespreviewer.py | 2 +- pitivi/timeline/layer.py | 6 ++++-- pitivi/timeline/timeline.py | 20 ++++++++++++-------- pitivi/transitions.py | 8 ++++---- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index cef0c637a..92989e922 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -116,7 +116,7 @@ class PreviewWidget(Gtk.Grid, Loggable): # Play button self.bbox = Gtk.Box() self.bbox.set_orientation(Gtk.Orientation.HORIZONTAL) - self.play_button = Gtk.ToolButton() + self.play_button = Gtk.Button() self.play_button.set_icon_name("media-playback-start") self.play_button.connect("clicked", self._on_start_stop_clicked_cb) self.bbox.prepend(self.play_button) diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py index dc3a5b8a1..ba7e5bf1d 100644 --- a/pitivi/timeline/layer.py +++ b/pitivi/timeline/layer.py @@ -413,8 +413,10 @@ class Layer(Gtk.Fixed, Loggable): self._children.sort(key=lambda clip: clip.z_order) for child in self._children: if isinstance(child, elements.TransitionClip): - window = child.get_window() - window.raise_() + # TODO: Replace using Xlib apis + # window = child.get_window() + # window.raise_() + pass self._changed = False for child in self._children: diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py index 0cf56b088..4526626e3 100644 --- a/pitivi/timeline/timeline.py +++ b/pitivi/timeline/timeline.py @@ -242,6 +242,8 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): Gtk.ScrolledWindow.__init__(self) Loggable.__init__(self) + self.props.hscrollbar_policy = Gtk.PolicyType.EXTERNAL + self.props.vscrollbar_policy = Gtk.PolicyType.EXTERNAL self.fixed = Gtk.Fixed() self.set_child(self.fixed) self._timeline = timeline @@ -251,13 +253,13 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): self.layers_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.layers_vbox.add_css_class("LayersBox") - self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER) self.fixed.put(self.layers_vbox, 0, 0) self.marquee = Marquee(timeline, self) self.fixed.put(self.marquee, 0, 0) - # self.layers_vbox.connect("size-allocate", self.__size_allocate_cb) + # TODO:Porting: find proper replacement + self.layers_vbox.connect("notify::width_request", self.__size_allocate_cb) def do_snapshot(self, snapshot): """Draws the children and indicators.""" @@ -293,12 +295,14 @@ class LayersLayout(Gtk.ScrolledWindow, Loggable): cr.line_to(xpos, height) cr.stroke() - # def __size_allocate_cb(self, unused_widget, allocation): - # """Sets the size of the scrollable area to fit the layers_vbox.""" - # self.log("The size of the layers_vbox changed: %sx%s", allocation.width, allocation.height) - # # The additional space is for the 'Add layer' button. - # self.set_max_content_width(allocation.width) - # self.set_max_content_height(allocation.height + LAYER_HEIGHT / 2) + def __size_allocate_cb(self, layers_vbox, unused_pspec): + """Sets the size of the scrollable area to fit the layers_vbox.""" + print("size allocate") + allocation = layers_vbox.get_allocation() + self.log("The size of the layers_vbox changed: %sx%s", allocation.width, allocation.height) + # The additional space is for the 'Add layer' button. + self.set_max_content_width(allocation.width) + self.set_max_content_height(allocation.height + LAYER_HEIGHT / 2) class FullLayersLayout(LayersLayout, Zoomable): diff --git a/pitivi/transitions.py b/pitivi/transitions.py index a88517bb3..3a4a1e428 100644 --- a/pitivi/transitions.py +++ b/pitivi/transitions.py @@ -167,8 +167,8 @@ class TransitionsListWidget(Gtk.Box, Loggable): self.iconview.connect("selection-changed", self._transition_selected_cb) self.border_scale.connect("value-changed", self._border_scale_cb) self.invert_checkbox.connect("toggled", self._invert_checkbox_cb) - self.border_mode_normal.connect("released", self._border_type_changed_cb) - self.border_mode_loop.connect("released", self._border_type_changed_cb) + self.border_mode_normal.connect("toggled", self._border_type_changed_cb) + self.border_mode_loop.connect("toggled", self._border_type_changed_cb) self.element.connect("notify::border", self.__updated_cb) self.element.connect("notify::invert", self.__updated_cb) self.element.connect("notify::transition-type", self.__updated_cb) @@ -319,7 +319,7 @@ class TransitionsListWidget(Gtk.Box, Loggable): return None def _iconview_query_tooltip_cb(self, view, x, y, keyboard_mode, tooltip): - is_row, x, y, model, path, iter_ = view.get_tooltip_context( + is_row, model, path, iter_ = view.get_tooltip_context( x, y, keyboard_mode) if not is_row: return False @@ -327,7 +327,7 @@ class TransitionsListWidget(Gtk.Box, Loggable): view.set_tooltip_item(tooltip, path) icon_name = model.get_value(iter_, COL_ICON_NAME) - tooltip.set_icon_from_icon_name(icon_name, Gtk.IconSize.LARGE) + tooltip.set_icon_from_icon_name(icon_name) longname = model.get_value(iter_, COL_NAME) description = model.get_value(iter_, COL_DESCRIPTION) -- GitLab From 984a14bfce2fe40c7bb46d2994edaa5bb5cfe2e8 Mon Sep 17 00:00:00 2001 From: rhythm Date: Sat, 29 Jul 2023 22:19:56 +0530 Subject: [PATCH 128/132] importing output.mp4 working --- output.mp4 | Bin 0 -> 272528 bytes pitivi/medialibrary.py | 17 ++++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 output.mp4 diff --git a/output.mp4 b/output.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..46604d34fb90d125d36d1ec363859b84e7f21337 GIT binary patch literal 272528 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 Date: Sat, 5 Aug 2023 18:19:12 +0530 Subject: [PATCH 129/132] Viewer: fix detached viewer --- pitivi/viewer/peak_meter.py | 2 +- pitivi/viewer/viewer.py | 39 +++++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/pitivi/viewer/peak_meter.py b/pitivi/viewer/peak_meter.py index 9c526534d..d7092fa61 100644 --- a/pitivi/viewer/peak_meter.py +++ b/pitivi/viewer/peak_meter.py @@ -25,7 +25,7 @@ from pitivi.utils.ui import set_cairo_color from pitivi.utils.ui import SPACING # The width for the peak meter -PEAK_METER_WIDTH = 8 +PEAK_METER_WIDTH = 10 # The maximum height for the peak meter PEAK_METER_MAX_HEIGHT = 200 # The minimum height for the peak meter diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py index bc4606f4e..66c0eb077 100644 --- a/pitivi/viewer/viewer.py +++ b/pitivi/viewer/viewer.py @@ -134,8 +134,9 @@ class ViewerContainer(Gtk.Box, Loggable): for i in range(project.audiochannels): if i > len(self.peak_meters) - 1: new_peak_meter = PeakMeter() - new_peak_meter.set_property("valign", Gtk.Align.FILL) - new_peak_meter.set_property("halign", Gtk.Align.CENTER) + new_peak_meter.set_vexpand(True) + new_peak_meter.set_valign(Gtk.Align.FILL) + new_peak_meter.set_halign(Gtk.Align.CENTER) new_peak_meter.set_margin_bottom(SPACING) new_peak_meter.set_margin_top(SPACING) self.peak_meters.append(new_peak_meter) @@ -187,13 +188,15 @@ class ViewerContainer(Gtk.Box, Loggable): self.viewer_row_box.prepend(self.target) if self.docked: - self.viewer_row_box.set_hexpand(True) - self.viewer_row_box.set_halign(Gtk.Align.FILL) + self.viewer_row_box.set_vexpand(True) + self.viewer_row_box.set_valign(Gtk.Align.FILL) self.prepend(self.viewer_row_box) else: self.viewer_row_box.set_hexpand(True) self.external_vbox.prepend(self.viewer_row_box) - self.external_vbox.child_set(self.viewer_row_box, fill=True) + # TODO:Porting: Check if this is needed + # self.external_vbox.child_set(self.viewer_row_box, fill=True) + # GObject.Object.set_property(self.viewer_row_box, "fill", True) self.target.show() @@ -226,10 +229,12 @@ class ViewerContainer(Gtk.Box, Loggable): # TODO: Porting: set viewerX and viewerY in the settings def _external_window_notify_default_width_cb(self, external_window, unused_pspec): - self.settings.viewerWidth = external_window.get_default_width() + width, unused_height = external_window.get_default_size() + self.settings.viewerWidth = width def _external_window_notify_default_height_cb(self, external_window, unused_pspec): - self.settings.viewerHeight = external_window.get_default_height() + unused_width, height = external_window.get_default_size() + self.settings.viewerHeight = height def _create_ui(self): """Creates the Viewer GUI.""" @@ -282,14 +287,17 @@ class ViewerContainer(Gtk.Box, Loggable): self.peak_meter_box.set_margin_start(SPACING) self.peak_meter_box.set_margin_bottom(SPACING) self.peak_meter_box.set_margin_top(SPACING) - self.peak_meter_box.set_property("valign", Gtk.Align.CENTER) + self.peak_meter_box.set_vexpand(True) + self.peak_meter_box.set_valign(Gtk.Align.FILL) self.peak_meters = [] # Peak Meter Scale self.peak_meter_scale = PeakMeterScale() - self.peak_meter_scale.set_property("valign", Gtk.Align.FILL) - self.peak_meter_scale.set_property("halign", Gtk.Align.CENTER) + self.peak_meter_scale.set_halign(Gtk.Align.CENTER) + self.peak_meter_scale.set_valign(Gtk.Align.FILL) + self.peak_meter_scale.set_vexpand(True) + self.peak_meter_scale.set_hexpand(False) self.peak_meter_scale.set_margin_start(SPACING) self.peak_meter_box.append(self.peak_meter_scale) self.viewer_row_box.append(self.peak_meter_box) @@ -298,8 +306,8 @@ class ViewerContainer(Gtk.Box, Loggable): # Buttons/Controls bbox = Gtk.Box() bbox.set_orientation(Gtk.Orientation.HORIZONTAL) - bbox.set_property("valign", Gtk.Align.CENTER) - bbox.set_property("halign", Gtk.Align.CENTER) + bbox.set_halign(Gtk.Align.CENTER) + bbox.set_valign(Gtk.Align.CENTER) bbox.set_margin_start(SPACING) bbox.set_margin_end(SPACING) self.append(bbox) @@ -565,8 +573,9 @@ class ViewerContainer(Gtk.Box, Loggable): self.external_window.show() self.hide() - self.external_window.move(self.settings.viewerX, self.settings.viewerY) - self.external_window.resize( + # TODO:Porting find replacement + # self.external_window.move(self.settings.viewerX, self.settings.viewerY) + self.external_window.set_default_size( self.settings.viewerWidth, self.settings.viewerHeight) if self.project: self.project.pipeline.pause() @@ -594,7 +603,7 @@ class ViewerContainer(Gtk.Box, Loggable): self.__create_new_viewer() self.undock_button.show() - self.fullscreen_button.destroy() + self.buttons_container.remove(self.fullscreen_button) self.external_vbox.remove(self.buttons_container) self.buttons_container.set_margin_bottom(0) self.append(self.buttons_container) -- GitLab From c54112a1a0648a7ea445b383bb3821ea2275c25a Mon Sep 17 00:00:00 2001 From: Jainil Patel Date: Wed, 9 Aug 2023 21:50:34 +0530 Subject: [PATCH 130/132] Gtk4-Port: Fix Previewer --- pitivi/editorperspective.py | 3 +-- pitivi/mediafilespreviewer.py | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 562eabcd2..f3dc74206 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -874,10 +874,9 @@ class PreviewAssetWindow(Gtk.Window): def preview(self): """Shows the window and starts the playback.""" width, height = self._calculate_preview_window_size() - self.resize(width, height) + self.set_default_size(width, height) # Setting the position of the window only works if it's currently hidden # otherwise, after the resize the position will not be readjusted - self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT) self.show() self._previewer.play() diff --git a/pitivi/mediafilespreviewer.py b/pitivi/mediafilespreviewer.py index 92989e922..20b3ae0df 100644 --- a/pitivi/mediafilespreviewer.py +++ b/pitivi/mediafilespreviewer.py @@ -137,10 +137,10 @@ class PreviewWidget(Gtk.Grid, Loggable): self.bbox.prepend(self.seeker) # Zoom buttons - self.b_zoom_in = Gtk.ToolButton() + self.b_zoom_in = Gtk.Button() self.b_zoom_in.set_icon_name("zoom-in") self.b_zoom_in.connect("clicked", self._on_zoom_clicked_cb, 1) - self.b_zoom_out = Gtk.ToolButton() + self.b_zoom_out = Gtk.Button() self.b_zoom_out.set_icon_name("zoom-out") self.b_zoom_out.connect("clicked", self._on_zoom_clicked_cb, -1) self.bbox.prepend(self.b_zoom_in) @@ -263,7 +263,7 @@ class PreviewWidget(Gtk.Grid, Loggable): video_height = video.get_natural_height() w, h = self.__get_best_size(video_width, video_height) self.preview_video.set_size_request(w, h) - self.preview_video.props.ratio = video_width / video_height + self.preview_video.ratio = video_width / video_height self.preview_video.show() self.bbox.show() self.play_button.show() -- GitLab From c83f88182fc4ecef9c71fdf4333ab8372063cdf9 Mon Sep 17 00:00:00 2001 From: rhythm Date: Sun, 23 Jul 2023 13:48:11 +0530 Subject: [PATCH 131/132] Closing Credits removing debug lines ability to change text on intial generation working temp closing clip generation working with html modification reloading assets working different types of cc working extra files deleted minor updates added file and updated workflowupdates --- build/flatpak/org.pitivi.Pitivi.json | 2 + ...LE-WEB_AUDIO-build-after-262451-main.patch | 34 ++ build/flatpak/wpe/wpe.json | 98 ++++++ data/closing_credits/template.html | 75 +++++ data/ui/specialclipdialog.ui | 76 +++++ data/ui/specialcliplibrary.ui | 30 ++ output.mp4 | Bin 272528 -> 0 bytes pitivi/application.py | 3 + pitivi/clipproperties.py | 65 ++++ pitivi/editorperspective.py | 5 + pitivi/specialclips.py | 303 ++++++++++++++++++ 11 files changed, 691 insertions(+) create mode 100644 build/flatpak/wpe/0001-Fix-ENABLE-WEB_AUDIO-build-after-262451-main.patch create mode 100644 build/flatpak/wpe/wpe.json create mode 100644 data/closing_credits/template.html create mode 100644 data/ui/specialclipdialog.ui create mode 100644 data/ui/specialcliplibrary.ui delete mode 100644 output.mp4 create mode 100644 pitivi/specialclips.py diff --git a/build/flatpak/org.pitivi.Pitivi.json b/build/flatpak/org.pitivi.Pitivi.json index f8348046a..1094522a6 100644 --- a/build/flatpak/org.pitivi.Pitivi.json +++ b/build/flatpak/org.pitivi.Pitivi.json @@ -41,6 +41,7 @@ "python3-matplotlib.json", "libcanberra/libcanberra.json", "python3-librosa.json", + "wpe/wpe.json", { "name": "gsound", "buildsystem": "meson", @@ -392,6 +393,7 @@ "-Dgst-plugins-good:doc=disabled", "-Dgst-plugins-good:dv=enabled", "-Dgst-plugins-ugly:doc=disabled", + "-Dgst-plugins-bad:wpe=enabled", "-Dgst-plugins-ugly:x264=enabled", "-Dgst-python:pygi-overrides-dir=/app/lib/python3.10/site-packages/gi/overrides/", "-Dgstreamer-vaapi:doc=disabled", diff --git a/build/flatpak/wpe/0001-Fix-ENABLE-WEB_AUDIO-build-after-262451-main.patch b/build/flatpak/wpe/0001-Fix-ENABLE-WEB_AUDIO-build-after-262451-main.patch new file mode 100644 index 000000000..9b892aca9 --- /dev/null +++ b/build/flatpak/wpe/0001-Fix-ENABLE-WEB_AUDIO-build-after-262451-main.patch @@ -0,0 +1,34 @@ +From b36decf27ea91f9ed21a4b46524d6c6781076d5c Mon Sep 17 00:00:00 2001 +From: Don Olmstead +Date: Fri, 31 Mar 2023 19:46:07 -0700 +Subject: [PATCH] Fix !ENABLE(WEB_AUDIO) build after 262451@main + https://bugs.webkit.org/show_bug.cgi?id=254852 + +Unreviewed build fix. + +Add !ENABLE(WEB_AUDIO) guard. + +* Source/WebCore/page/MemoryRelease.cpp: + +Canonical link: https://commits.webkit.org/262461@main +--- + Source/WebCore/page/MemoryRelease.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Source/WebCore/page/MemoryRelease.cpp b/Source/WebCore/page/MemoryRelease.cpp +index a4f208c17e64..438c2cb00cf2 100644 +--- a/Source/WebCore/page/MemoryRelease.cpp ++++ b/Source/WebCore/page/MemoryRelease.cpp +@@ -103,7 +103,9 @@ static void releaseCriticalMemory(Synchronous synchronous, MaintainBackForwardCa + } + + CSSValuePool::singleton().drain(); ++#if ENABLE(WEB_AUDIO) + HRTFElevation::clearCache(); ++#endif + + Page::forEachPage([](auto& page) { + page.cookieJar().clearCache(); +-- +2.34.1 + diff --git a/build/flatpak/wpe/wpe.json b/build/flatpak/wpe/wpe.json new file mode 100644 index 000000000..4d58007ca --- /dev/null +++ b/build/flatpak/wpe/wpe.json @@ -0,0 +1,98 @@ +{ + "name": "wpe", + "buildsystem": "simple", + "build-commands": [], + "modules": [ + { + "name": "unifdef", + "buildsystem": "simple", + "build-commands": [ + "make prefix=/app install" + ], + "sources": [ + { + "type": "archive", + "url": "https://dotat.at/prog/unifdef/unifdef-2.12.tar.gz", + "sha256": "fba564a24db7b97ebe9329713ac970627b902e5e9e8b14e19e024eb6e278d10b" + } + ] + }, + { + "name": "libyuv", + "buildsystem": "cmake", + "config-opts": [ + "-DCMAKE_INSTALL_PREFIX=/app", + "-DCMAKE_INSTALL_LIBDIR=lib" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/lemenkov/libyuv/archive/master.tar.gz", + "sha256" : "599aed0edb5e95a582f6fe5cd4c11ff21a3dd656352601488fa8bc4cdb27d38d" + } + ] + }, + { + "name": "libavif", + "buildsystem": "cmake", + "config-opts": [ + "-DCMAKE_INSTALL_PREFIX=/app", + "-DCMAKE_INSTALL_LIBDIR=lib" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/AOMediaCodec/libavif/archive/refs/tags/v0.9.2.tar.gz", + "sha256" : "d6607d654adc40a392da83daa72a4ff802cd750c045a68131c9305639c10fc5c" + } + ] + }, + { + "name": "libsoup", + "buildsystem": "meson", + "sources": [ + { + "type": "archive", + "url": "https://download.gnome.org/sources/libsoup/2.72/libsoup-2.72.0.tar.xz", + "sha256" : "170c3f8446b0f65f8e4b93603349172b1085fb8917c181d10962f02bb85f5387" + } + ] + }, + { + "name": "wpe-webkit", + "buildsystem": "cmake-ninja", + "config-opts": [ + "-DPORT=WPE", + "-DENABLE_UNIFIED_BUILDS=NO", + "-DCMAKE_BUILD_TYPE=Release", + "-DENABLE_API_TESTS=OFF", + "-DUSE_SOUP2=ON", + "-DENABLE_DOCUMENTATION=NO", + "-DENABLE_INTROSPECTION=NO", + "-DENABLE_BUBBLEWRAP_SANDBOX=NO", + "-DENABLE_MINIBROWSER=OFF", + "-DENABLE_TOOLS=OFF", + "-DENABLE_VIDEO=OFF", + "-DENABLE_WEB_AUDIO=OFF", + "-DDEBUG_FISSION=ON", + "-DCMAKE_INSTALL_PREFIX=/app", + "-DCMAKE_INSTALL_LIBDIR=lib" + ], + "sources": [ + { + "type": "archive", + "url": "https://wpewebkit.org/releases/wpewebkit-2.40.1.tar.xz", + "sha256": "c6b25e168b70f2121305ed078d0790e0aa4b0c73fce44e32ed42d4e5dd137ccb" + }, + { + "type": "patch", + "path": "0001-Fix-ENABLE-WEB_AUDIO-build-after-262451-main.patch" + } + ], + "env": { + "CC": "/usr/bin/cc", + "CXX": "/usr/bin/c++" + } + } + ] +} diff --git a/data/closing_credits/template.html b/data/closing_credits/template.html new file mode 100644 index 000000000..7d9f7d4d7 --- /dev/null +++ b/data/closing_credits/template.html @@ -0,0 +1,75 @@ + + + + + + + +Closing Credit Clip + + +

+
+

Directed By

+

Rhythm Narula

+

Screenplay By

+

Alan Silvestri

+

Produced By

+

Joanna Johnston

+

Director of Photography

+

Ken Ralston

+

Digital Artist

+

Thibault Saunier

+

Musicians

+

Rhythm Narula

+

Digital Artist

+

Alexandru Băluț

+

Costumes Designed By

+

Andy Guthenberg/p> +

Co-Producers

+

Rhythm Narula

+

+

Additional Visual Effects by WETA, LTD

+

Wellington, New Zealand

+

+

First-Assistant Camera - Tony Rivetti

+

Second-Assistant Camera - Frank D. Parish

+

Aerial Coordinator - Kevin La Rosa

+

+

Visual Effects Supervisor- Stephen Rosenbaum

+
+

Filmed in PANAVISION

+

Color and prints by TECHNICOLOR

+

Kodak Motion Picture Products

+ +
+
+ + diff --git a/data/ui/specialclipdialog.ui b/data/ui/specialclipdialog.ui new file mode 100644 index 000000000..88267ce86 --- /dev/null +++ b/data/ui/specialclipdialog.ui @@ -0,0 +1,76 @@ + + + + + Please enter text + + + Special Clip Settings + + + + vertical + 12 + 5 + 5 + 5 + 5 + + + + + + + True + True + + + True + True + True + True + textbuffer1 + + + + + + + + 0 + 0 + 2 + + + + + + + button8 + ok_button + + + + 5 + 5 + 5 + 5 + + + Cancel + 1 + 1 + 5 + + + + + OK + 1 + 1 + + + + + + diff --git a/data/ui/specialcliplibrary.ui b/data/ui/specialcliplibrary.ui new file mode 100644 index 000000000..133b0c7da --- /dev/null +++ b/data/ui/specialcliplibrary.ui @@ -0,0 +1,30 @@ + + + + + + + + 5 + 1 + 1 + 1 + Search... + + + + + + Insert the selected clips at the end of the timeline + medialibrary.insert-assets-at-end + 1 + insert-object-symbolic + + media_insert_button + + + + + diff --git a/output.mp4 b/output.mp4 deleted file mode 100644 index 46604d34fb90d125d36d1ec363859b84e7f21337..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 272528 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 None: + Gtk.Expander.__init__(self) + Loggable.__init__(self) + + self.set_expanded(True) + self.set_label(_("Closing Credit")) + + self.app = app + self.project = self.app.project_manager.current_project + self._clip: Optional[GES.Clip] = None + self.change_text_button = Gtk.Button(label="Change Text") + self.change_text_button.props.halign = Gtk.Align.CENTER + self.change_text_button.props.margin_top = PADDING + self.change_text_button.props.margin_bottom = PADDING + self.change_text_button.props.margin_start = PADDING + self.change_text_button.props.margin_end = PADDING + self.change_text_button.connect("clicked", self.button_clicked_cb) + + self.name_store = Gtk.ListStore(str) + self.name_store.append([_("Center")]) + self.name_store.append([_("Right")]) + self.name_store.append([_("Left")]) + + self.name_combo = Gtk.ComboBox.new_with_model_and_entry(self.name_store) + self.name_combo.set_entry_text_column(0) + + self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + self.hbox.append(self.change_text_button) + self.hbox.append(self.name_combo) + + self.set_child(self.hbox) + self.hide() + + def button_clicked_cb(self, unused_widget): + active_iter = self.name_combo.get_active_iter() + clip_name = self.name_store.get_value(active_iter, 0) + dialog = SpecialClipSettingsDialog(self.app.gui, self.app, clip_name, self._clip) + dialog.window.set_modal(True) + dialog.window.show() + + def set_clip(self, clip): + if clip is None: + return + + if not clip or not isinstance(clip, GES.SourceClip): + self.hide() + + if "closing_credit" not in clip.get_asset().get_meta("pitivi::tags"): + self.hide() + return + + self._clip = clip + self.show() diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index f3dc74206..40aafe18a 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -36,6 +36,7 @@ from pitivi.mediafilespreviewer import PreviewWidget from pitivi.medialibrary import MediaLibraryWidget from pitivi.perspective import Perspective from pitivi.settings import GlobalSettings +from pitivi.specialclips import SpecialClipWidget from pitivi.tabsmanager import BaseTabs from pitivi.timeline.previewers import ThumbnailCache from pitivi.timeline.timeline import TimelineContainer @@ -209,13 +210,17 @@ class EditorPerspective(Perspective, Loggable): self.main_tabs = BaseTabs(self.app) self.medialibrary = MediaLibraryWidget(self.app) self.effectlist = EffectListWidget(self.app) + self.specialcliplist = SpecialClipWidget(self.app) self.main_tabs.append_page("Media Library", self.medialibrary, Gtk.Label.new(_("Media Library"))) self.main_tabs.append_page("Effect Library", self.effectlist, Gtk.Label.new(_("Effect Library"))) + self.main_tabs.append_page("Special Clips", + self.specialcliplist, Gtk.Label.new(_("Special Clips"))) self.medialibrary.connect('play', self._media_library_play_cb) self.medialibrary.show() self.effectlist.show() + self.specialcliplist.show() # Second set of tabs self.context_tabs = BaseTabs(self.app) diff --git a/pitivi/specialclips.py b/pitivi/specialclips.py new file mode 100644 index 000000000..f42e7bba6 --- /dev/null +++ b/pitivi/specialclips.py @@ -0,0 +1,303 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Rhythm Narula +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +"""Classes for handling Special Clips.""" +import os + +from gi.repository import GES +from gi.repository import GLib +from gi.repository import Gst +from gi.repository import Gtk + +from pitivi.configure import get_ui_dir +from pitivi.utils.loggable import Loggable +from pitivi.utils.ui import get_widget_children +from pitivi.utils.ui import SPACING + +SPECIAL_CLIPS_INFO = { + 'Closing Credit Clip': [ + ['Center', 'Place the content at center'], + ['Right', 'Place the content at the right'], + ['Left', 'Place the content at the left'], + ], + 'Audio Clip': [ + ['Jingle Bell', 'Play Jingle bell sound'], + ] +} + +ICON_WIDTH = 80 +ICON_HEIGHT = 45 + + +class ClipInfo: + """Info for displaying and using a special clip. + + Attributes: + clip_name (str): Used for identifying the clip type, example - closing_credit_clip. + clip_category (str): Used for identifying further category, example - Center, Left or Right. + clip_description (str): Used for describing the effect. + """ + + def __init__(self, clip_name, clip_category, clip_description): + self.clip_name = clip_name + self.clip_category = clip_category + self.clip_description = clip_description + + +class SpecialClipManager(Loggable): + """Keeps info about effects and their categories. + + Attributes: + SPECIAL_CLIPS_INFO : The available effects. + """ + + def __init__(self): + Loggable.__init__(self) + self._special_clips = {} + for clip_type in SPECIAL_CLIPS_INFO.items(): + clips = clip_type[1] + for clip in clips: + clip_info = ClipInfo(clip[0], clip_type[0], clip[1]) + self._special_clips[clip[0]] = clip_info + + +class SpecialClipWidget(Gtk.Box, Loggable): + """Widget for managing special clips. + + Attributes: + app (Pitivi): The app. + """ + + def __init__(self, app): + Gtk.Box.__init__(self) + Loggable.__init__(self) + + self.app = app + self.set_orientation(Gtk.Orientation.VERTICAL) + builder = Gtk.Builder(self) + builder.add_from_file(os.path.join(get_ui_dir(), "specialcliplibrary.ui")) + toolbar = builder.get_object("specialcliplibrary_box") + self.search_entry = builder.get_object("search_entry") + + self.main_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + + self.category_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.category_view.set_hexpand(True) + self.category_view.set_halign(Gtk.Align.FILL) + self.main_view.prepend(self.category_view) + + scrollwin = Gtk.ScrolledWindow() + scrollwin.props.hscrollbar_policy = Gtk.PolicyType.NEVER + scrollwin.props.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC + scrollwin.set_vexpand(True) + scrollwin.set_valign(Gtk.Align.FILL) + scrollwin.set_child(self.main_view) + + self.prepend(toolbar) + self.prepend(scrollwin) + + GLib.idle_add(self._load_available_clips_cb) + + def _load_available_clips_cb(self): + self._set_up_category_view() + + def _set_up_category_view(self): + """Adds expanders and clip types to the category view.""" + for category in SPECIAL_CLIPS_INFO: + widget = self._create_category_widget(category) + self.category_view.append(widget) + + for expander in get_widget_children(self.category_view): + listbox = expander.get_child() + category_name = expander.get_label() + self._add_effects_to_listbox(listbox, category_name) + + self.category_view.show() + + def _create_category_widget(self, category): + """Creates an expander for the given category.""" + expander = Gtk.Expander( + label=category, + margin_top=SPACING, + margin_bottom=SPACING, + margin_start=SPACING, + margin_end=SPACING + ) + + listbox = Gtk.ListBox(activate_on_single_click=False) + listbox.connect("row-activated", self._effects_listbox_row_activated_cb) + expander.set_child(listbox) + return expander + + def _effects_listbox_row_activated_cb(self, listbox, row): + """Handles the activation of a row representing a clip.""" + effect_box = row.get_first_child() + dialog = SpecialClipSettingsDialog(self.app.gui, self.app, effect_box.clip_name, None) + dialog.window.set_modal(True) + dialog.window.show() + + def _add_effects_to_listbox(self, listbox, category=None): + """Adds effect rows to the given listbox.""" + for clips in SPECIAL_CLIPS_INFO[category]: + widget = self._create_effect_widget(clips[0], clips[1]) + listbox.insert(widget, -1) + + def _create_effect_widget(self, clip_name, clip_description): + clip_box = Gtk.Box( + orientation=Gtk.Orientation.HORIZONTAL, + margin_top=SPACING / 2, + margin_bottom=SPACING / 2, + margin_start=SPACING / 2, + margin_end=SPACING / 2 + ) + clip_box.clip_name = clip_name + clip_box.set_tooltip_text(clip_description) + label = Gtk.Label.new(clip_name) + label.set_xalign(0) + label.set_halign(Gtk.Align.FILL) + label.set_hexpand(True) + + clip_box.prepend(label) + row = Gtk.ListBoxRow(selectable=False) + row.set_child(clip_box) + return row + + +class SpecialClipSettingsDialog: + """Manager of a dialog for viewing and changing the special clip settings. + + Attributes: + parent_window : Window from which this widget is called. + app (Pitivi): The current app. + clip_name : Type of the clip, example - center, right or left. + clip : Clip to be modified. + """ + + def __init__(self, parent_window, app, clip_name, clip): + self.app = app + self.project = self.app.project_manager.current_project + + self.proxy_aspect_ratio = Gst.Fraction(1, 0) + + self.text_entered = "" + self.placeholder_str = """

Directed By

+

Rhythm Narula

+

Screenplay By

+

Alan Silvestri

+

Produced By

+

Joanna Johnston

+

Director of Photography

+

Ken Ralston

+

Digital Artist

+

Thibault Saunier

+

Musicians

+

Rhythm Narula

+

Digital Artist

+

Alexandru Băluț

+

Costumes Designed By

+

Andy Guthenberg/p> +

Co-Producers

+

Rhythm Narula

+

+

Additional Visual Effects by WETA, LTD

+

Wellington, New Zealand

+

+

First-Assistant Camera - Tony Rivetti

+

Second-Assistant Camera - Frank D. Parish

+

Aerial Coordinator - Kevin La Rosa

+

+

Visual Effects Supervisor- Stephen Rosenbaum

+
+

Filmed in PANAVISION

+

Color and prints by TECHNICOLOR

+

Kodak Motion Picture Products

+ """ + self.clip_name = clip_name + self.clip = clip + self._create_ui() + self.window.set_transient_for(parent_window) + + def _create_ui(self): + """Creates UI of the Text Editor to enter content to be displayed on clip.""" + self.builder = Gtk.Builder(self) + self.builder.add_from_file( + os.path.join(get_ui_dir(), "specialclipdialog.ui")) + self.window = self.builder.get_object("specialclip-settings-dialog") + self.window.set_size_request(600, 700) + + self.text_entry = self.builder.get_object("text_entry") + self.textbuf = self.builder.get_object("textview1").get_buffer() + self.textbuf.set_text(self.placeholder_str) + + def _response_cb(self, unused_widget, response): + """Handles the dialog being closed.""" + if response == Gtk.ResponseType.OK: + self._update_details() + self.window.destroy() + + def _update_details(self): + """Updates text entered and handles the generation/modification of clip.""" + self.text_entered = self.textbuf.get_text(self.textbuf.get_start_iter(), self.textbuf.get_end_iter(), True) + if self.clip is None: + self._generate_closing_credit_clip() + else: + self._update_closing_credit_clip() + + def _generate_closing_credit_clip(self): + """Handles the generation and addition of generated closing credit clip to project.""" + self._generate_html() + self._generate_clip("output.mp4") + filenames = [os.getcwd() + "/output.mp4"] + self.project.add_uris(filenames) + assets = GES.list_assets(GES.UriClip) + for asset in assets: + if os.path.basename(asset.get_id()) == 'output.mp4': + asset.set_meta("pitivi::tags", "closing_credit") + + def _update_closing_credit_clip(self): + """Handles the modification and reloading of the selected clip.""" + self._generate_html() + self._generate_clip(self.clip.get_uri()[7:]) + GES.Asset.needs_reload(GES.UriClip, self.clip.get_asset().props.id) + self.clip = None + + def _generate_html(self): + """Modifies the HTML with the entered text and type to be used to generate clip.""" + with open("data/closing_credits/template.html", "r", encoding="utf-8") as file: + template_content = file.read() + + template_content = template_content.replace("{{clip_content}}", self.text_entered) + template_content = template_content.replace("Center", self.clip_name) + + with open("data/closing_credits/template.html", "w", encoding="utf-8") as html_file: + html_file.write(template_content) + + def _generate_clip(self, output_clip_path): + """Generate clip using wpe package taking HTML as input and stores it in output_clip_path location.""" + file_uri = Gst.filename_to_uri(os.getcwd() + "/data/closing_credits/template.html") + pipe = Gst.Pipeline() + pipe = Gst.parse_launch("wpevideosrc num-buffers=200 location=" + file_uri + " draw-background=0 ! video/x-raw,framerate=30/1 ! videoconvert ! x264enc ! mp4mux ! filesink location=" + output_clip_path) + pipe.set_state(Gst.State.PLAYING) + bus = pipe.get_bus() + msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) + if msg.type == Gst.MessageType.ERROR: + err, debug = msg.parse_error() + print("Error received from element %s: %s" % (msg.src.get_name(), err)) + print("Debugging information: %s" % debug) + elif msg.type == Gst.MessageType.EOS: + print("End-Of-Stream reached.") + else: + print("Unexpected message received.") + pipe.set_state(Gst.State.NULL) -- GitLab From f13e4022da1e38f85bbf233ce8cc9f653df32ba1 Mon Sep 17 00:00:00 2001 From: rhythm Date: Thu, 24 Aug 2023 11:57:21 +0530 Subject: [PATCH 132/132] workflow updated --- data/closing_credits/template.html | 75 ----- data/closing_credits/template.txt | 45 +++ ...pdialog.ui => closingcreditsclipdialog.ui} | 12 +- data/ui/specialcliplibrary.ui | 30 -- pitivi/application.py | 3 - pitivi/clipproperties.py | 134 ++++---- pitivi/closingcreditsperspective.py | 171 ++++++++++ pitivi/editorperspective.py | 5 - pitivi/specialclips.py | 303 ------------------ pitivi/utils/misc.py | 2 +- 10 files changed, 297 insertions(+), 483 deletions(-) delete mode 100644 data/closing_credits/template.html create mode 100644 data/closing_credits/template.txt rename data/ui/{specialclipdialog.ui => closingcreditsclipdialog.ui} (88%) delete mode 100644 data/ui/specialcliplibrary.ui create mode 100644 pitivi/closingcreditsperspective.py delete mode 100644 pitivi/specialclips.py diff --git a/data/closing_credits/template.html b/data/closing_credits/template.html deleted file mode 100644 index 7d9f7d4d7..000000000 --- a/data/closing_credits/template.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - -Closing Credit Clip - - -
-
-

Directed By

-

Rhythm Narula

-

Screenplay By

-

Alan Silvestri

-

Produced By

-

Joanna Johnston

-

Director of Photography

-

Ken Ralston

-

Digital Artist

-

Thibault Saunier

-

Musicians

-

Rhythm Narula

-

Digital Artist

-

Alexandru Băluț

-

Costumes Designed By

-

Andy Guthenberg/p> -

Co-Producers

-

Rhythm Narula

-

-

Additional Visual Effects by WETA, LTD

-

Wellington, New Zealand

-

-

First-Assistant Camera - Tony Rivetti

-

Second-Assistant Camera - Frank D. Parish

-

Aerial Coordinator - Kevin La Rosa

-

-

Visual Effects Supervisor- Stephen Rosenbaum

-
-

Filmed in PANAVISION

-

Color and prints by TECHNICOLOR

-

Kodak Motion Picture Products

- -
-
- - diff --git a/data/closing_credits/template.txt b/data/closing_credits/template.txt new file mode 100644 index 000000000..34ef01a23 --- /dev/null +++ b/data/closing_credits/template.txt @@ -0,0 +1,45 @@ + + + + + + + +Closing Credit Clip + + +
+
+ {content} +
+
+ + diff --git a/data/ui/specialclipdialog.ui b/data/ui/closingcreditsclipdialog.ui similarity index 88% rename from data/ui/specialclipdialog.ui rename to data/ui/closingcreditsclipdialog.ui index 88267ce86..8b57f5647 100644 --- a/data/ui/specialclipdialog.ui +++ b/data/ui/closingcreditsclipdialog.ui @@ -4,7 +4,7 @@ Please enter text - + Special Clip Settings @@ -43,6 +43,16 @@ + + + + + true + + + + +
diff --git a/data/ui/specialcliplibrary.ui b/data/ui/specialcliplibrary.ui deleted file mode 100644 index 133b0c7da..000000000 --- a/data/ui/specialcliplibrary.ui +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - 5 - 1 - 1 - 1 - Search... - - - - - - Insert the selected clips at the end of the timeline - medialibrary.insert-assets-at-end - 1 - insert-object-symbolic - - media_insert_button - - - - - diff --git a/pitivi/application.py b/pitivi/application.py index 683942a9d..dc9f6bc47 100644 --- a/pitivi/application.py +++ b/pitivi/application.py @@ -37,7 +37,6 @@ from pitivi.settings import GlobalSettings from pitivi.settings import xdg_cache_home from pitivi.shortcuts import ShortcutsManager from pitivi.shortcuts import show_shortcuts -from pitivi.specialclips import SpecialClipManager from pitivi.undo.project import ProjectObserver from pitivi.undo.undo import UndoableActionLog from pitivi.utils import loggable @@ -77,7 +76,6 @@ class Pitivi(Gtk.Application, Loggable): self.settings: Optional[GlobalSettings] = None self.threads: Optional[ThreadMaster] = None self.effects: Optional[EffectsManager] = None - self.special_clips: Optional[SpecialClipManager] = None self.system: Optional[System] = None self.project_manager = ProjectManager(self) @@ -147,7 +145,6 @@ class Pitivi(Gtk.Application, Loggable): self.settings = GlobalSettings() self.threads = ThreadMaster() self.effects = EffectsManager() - self.special_clips = SpecialClipManager() self.proxy_manager = ProxyManager(self) self.system = get_system() self.plugin_manager = PluginManager(self) diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py index 2190cab00..3f3b04ea3 100644 --- a/pitivi/clipproperties.py +++ b/pitivi/clipproperties.py @@ -39,13 +39,13 @@ from pitivi.clip_properties.color import ColorProperties from pitivi.clip_properties.compositing import CompositingProperties from pitivi.clip_properties.markers import ClipMarkersProperties from pitivi.clip_properties.title import TitleProperties +from pitivi.closingcreditsperspective import ClosingCreditsPerspective from pitivi.configure import get_pixmap_dir from pitivi.configure import get_ui_dir from pitivi.configure import in_devel from pitivi.effects import EffectsPopover from pitivi.effects import EffectsPropertiesManager from pitivi.effects import HIDDEN_EFFECTS -from pitivi.specialclips import SpecialClipSettingsDialog from pitivi.trackerperspective import CoverObjectPopover from pitivi.undo.timeline import CommitTimelineFinalizingAction from pitivi.utils.custom_effect_widgets import create_custom_prop_widget_cb @@ -109,6 +109,10 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): self.clips_box.show() vbox.append(self.clips_box) + self.closing_clip_expander = ClosingClipProperties(app) + self.closing_clip_expander.set_vexpand(False) + vbox.append(self.closing_clip_expander) + self.transformation_expander = TransformationProperties(app) self.transformation_expander.set_vexpand(False) vbox.append(self.transformation_expander) @@ -134,10 +138,6 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): self.effect_expander.set_vexpand(False) vbox.append(self.effect_expander) - self.closing_clip_expander = ClosingClipProperties(app) - self.closing_clip_expander.set_vexpand(False) - vbox.append(self.closing_clip_expander) - self.marker_expander = ClipMarkersProperties(app) self.marker_expander.set_vexpand(False) vbox.append(self.marker_expander) @@ -147,13 +147,13 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): disable_scroll(vbox) + self.closing_clip_expander.set_clip(None) self.transformation_expander.set_source(None) self.speed_expander.set_clip(None) self.title_expander.set_source(None) self.color_expander.set_source(None) self.compositing_expander.set_source(None) self.effect_expander.set_clip(None) - self.closing_clip_expander.set_clip(None) self.marker_expander.set_clip(None) self._project = None @@ -194,6 +194,15 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): self._color_button.props.margin_end = SPACING box.append(self._color_button) + self._title_button = Gtk.Button() + self._title_button.set_label(_("Create closing credits clip")) + self._title_button.connect("clicked", self.create_closing_credits_clip_cb) + self._title_button.props.margin_top = SPACING + self._title_button.props.margin_bottom = SPACING + self._title_button.props.margin_start = SPACING + self._title_button.props.margin_end = SPACING + box.append(self._title_button) + return box def create_title_clip_cb(self, unused_button): @@ -233,6 +242,11 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): self.app.gui.editor.timeline_ui.insert_clips_on_first_layer([color_clip]) self._selection.set_selection([color_clip], SELECT) + def create_closing_credits_clip_cb(self, unused_widget): + dialog = ClosingCreditsPerspective(self.app.gui, self.app, None) + dialog.window.set_modal(True) + dialog.window.show() + def set_project(self, project, timeline_ui): if self._project: self._selection.disconnect_by_func(self._selection_changed_cb) @@ -259,13 +273,13 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable): elif isinstance(child, GES.VideoTestSource): color_clip_source = child + self.closing_clip_expander.set_clip(ges_clip if (not title_source and not color_clip_source) else None) self.transformation_expander.set_source(video_source) self.speed_expander.set_clip(ges_clip if (not title_source and not color_clip_source) else None) self.title_expander.set_source(title_source) self.color_expander.set_source(color_clip_source) self.compositing_expander.set_source(video_source) self.effect_expander.set_clip(ges_clip) - self.closing_clip_expander.set_clip(ges_clip if (not title_source and not color_clip_source) else None) self.marker_expander.set_clip(ges_clip) self.app.gui.editor.viewer.overlay_stack.select(video_source) @@ -275,6 +289,54 @@ def is_time_effect(effect): return bool(effect.get_meta(TimeProperties.TIME_EFFECT_META)) and in_devel() +class ClosingClipProperties(Gtk.Expander, Loggable): + """Widget for configuring closing credits clip.""" + + def __init__(self, app: Gtk.Application) -> None: + Gtk.Expander.__init__(self) + Loggable.__init__(self) + + self.set_expanded(True) + self.set_label(_("Edit Closing Credits")) + self._clip = None + + self.app = app + self.project = self.app.project_manager.current_project + self.change_text_button = Gtk.Button(label="Edit Clip") + self.change_text_button.props.halign = Gtk.Align.CENTER + self.change_text_button.props.margin_top = PADDING + self.change_text_button.props.margin_bottom = PADDING + self.change_text_button.props.margin_start = PADDING + self.change_text_button.props.margin_end = PADDING + self.change_text_button.connect("clicked", self._button_clicked_cb) + + self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + self.hbox.props.halign = Gtk.Align.CENTER + self.hbox.append(self.change_text_button) + + self.set_child(self.hbox) + self.hide() + + def _button_clicked_cb(self, unused_widget): + dialog = ClosingCreditsPerspective(self.app.gui, self.app, self._clip) + dialog.window.set_modal(True) + dialog.window.show() + + def set_clip(self, clip): + if clip is None: + return + + if not clip or not isinstance(clip, GES.SourceClip): + self.hide() + + if "closing_credit" not in clip.get_asset().get_meta("pitivi::tags"): + self.hide() + return + + self._clip = clip + self.show() + + class TimeProperties(Gtk.Expander, Loggable): """Widget for setting the time related properties of a clip. @@ -1355,61 +1417,3 @@ class TransformationProperties(Gtk.Expander, Loggable): self.source.connect("control-binding-removed", self._control_bindings_changed) self.set_visible(bool(self.source)) - - -class ClosingClipProperties(Gtk.Expander, Loggable): - """Widget for configuring text of the closing credit clip.""" - - def __init__(self, app: Gtk.Application) -> None: - Gtk.Expander.__init__(self) - Loggable.__init__(self) - - self.set_expanded(True) - self.set_label(_("Closing Credit")) - - self.app = app - self.project = self.app.project_manager.current_project - self._clip: Optional[GES.Clip] = None - self.change_text_button = Gtk.Button(label="Change Text") - self.change_text_button.props.halign = Gtk.Align.CENTER - self.change_text_button.props.margin_top = PADDING - self.change_text_button.props.margin_bottom = PADDING - self.change_text_button.props.margin_start = PADDING - self.change_text_button.props.margin_end = PADDING - self.change_text_button.connect("clicked", self.button_clicked_cb) - - self.name_store = Gtk.ListStore(str) - self.name_store.append([_("Center")]) - self.name_store.append([_("Right")]) - self.name_store.append([_("Left")]) - - self.name_combo = Gtk.ComboBox.new_with_model_and_entry(self.name_store) - self.name_combo.set_entry_text_column(0) - - self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - self.hbox.append(self.change_text_button) - self.hbox.append(self.name_combo) - - self.set_child(self.hbox) - self.hide() - - def button_clicked_cb(self, unused_widget): - active_iter = self.name_combo.get_active_iter() - clip_name = self.name_store.get_value(active_iter, 0) - dialog = SpecialClipSettingsDialog(self.app.gui, self.app, clip_name, self._clip) - dialog.window.set_modal(True) - dialog.window.show() - - def set_clip(self, clip): - if clip is None: - return - - if not clip or not isinstance(clip, GES.SourceClip): - self.hide() - - if "closing_credit" not in clip.get_asset().get_meta("pitivi::tags"): - self.hide() - return - - self._clip = clip - self.show() diff --git a/pitivi/closingcreditsperspective.py b/pitivi/closingcreditsperspective.py new file mode 100644 index 000000000..a51189bf7 --- /dev/null +++ b/pitivi/closingcreditsperspective.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Rhythm Narula +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see . +"""Handling Closing Credits Clip.""" +import os +from gettext import gettext as _ + +from gi.repository import GES +from gi.repository import Gst +from gi.repository import Gtk + +from pitivi.configure import get_ui_dir +from pitivi.utils.loggable import Loggable + + +class ClosingCreditsPerspective(Loggable): + """Manager of a dialog for generating closing credits clip. + + Attributes: + parent_window : Window from which this widget is called. + app (Pitivi): The current app. + clip_name : Type of the clip, example - center, right or left. + clip : Clip to be modified. + """ + + def __init__(self, parent_window, app, clip): + self.app = app + self.project = self.app.project_manager.current_project + Loggable.__init__(self) + + self.proxy_aspect_ratio = Gst.Fraction(1, 0) + + self.text_entered = "" + self.placeholder_str = """

Directed By

+

Rhythm Narula

+

Screenplay By

+

Alan Silvestri

+

Produced By

+

Joanna Johnston

+

Director of Photography

+

Ken Ralston

+

Digital Artist

+

Thibault Saunier

+

Musicians

+

Rhythm Narula

+

Digital Artist

+

Alexandru Băluț

+

Costumes Designed By

+

Andy Guthenberg/p> +

Co-Producers

+

Rhythm Narula

+

+

Additional Visual Effects by WETA, LTD

+

Wellington, New Zealand

+

+

First-Assistant Camera - Tony Rivetti

+

Second-Assistant Camera - Frank D. Parish

+

Aerial Coordinator - Kevin La Rosa

+

+

Visual Effects Supervisor- Stephen Rosenbaum

+
+

Filmed in PANAVISION

+

Color and prints by TECHNICOLOR

+

Kodak Motion Picture Products

+ """ + self.clip_types = [_("Center"), _("Right"), _("Left")] + self.clip_name = self.clip_types[0] + self.clip = clip + self._create_ui() + self.window.set_transient_for(parent_window) + + def _create_ui(self): + """Creates UI of the Text Editor to enter content to be displayed on clip.""" + self.builder = Gtk.Builder(self) + self.builder.add_from_file( + os.path.join(get_ui_dir(), "closingcreditsclipdialog.ui")) + self.window = self.builder.get_object("closingcredits-settings-dialog") + self.window.set_size_request(600, 700) + + self.combo_box = self.builder.get_object("combo_box") + self._populate_combo_box() + + self.text_entry = self.builder.get_object("text_entry") + self.textbuf = self.builder.get_object("textview1").get_buffer() + if self.clip is not None: + self.placeholder_str = self.clip.get_asset().get_meta("pitivi::clip_content") + self.clip_name = self.clip.get_asset().get_meta("pitivi::clip_type") + self.textbuf.set_text(self.placeholder_str) + + def _populate_combo_box(self): + """Populates the dropdown with available clip types.""" + for clip_name in self.clip_types: + self.combo_box.append_text(clip_name) + self.combo_box.set_active(0) + + def on_combo_changed(self, combo): + self.clip_name = combo.get_active_text() + + def _response_cb(self, unused_widget, response): + """Handles the dialog being closed.""" + if response == Gtk.ResponseType.OK: + self._update_details() + self.window.destroy() + + def _update_details(self): + """Updates text entered and handles the generation/modification of clip.""" + self.text_entered = self.textbuf.get_text(self.textbuf.get_start_iter(), self.textbuf.get_end_iter(), True) + if self.clip is None: + self._generate_closing_credit_clip() + else: + self._update_closing_credit_clip() + + def _generate_closing_credit_clip(self): + """Handles the generation and addition of generated closing credit clip to project.""" + self._generate_html() + self._generate_clip("output.mp4") + filenames = [Gst.filename_to_uri(os.getcwd() + "/output.mp4")] + self.project.add_uris(filenames) + assets = GES.list_assets(GES.UriClip) + for asset in assets: + if os.path.basename(asset.get_id()) == 'output.mp4': + asset.set_meta("pitivi::tags", "closing_credit") + asset.set_meta("pitivi::clip_content", self.text_entered) + asset.set_meta("pitivi::clip_type", self.clip_name) + + def _update_closing_credit_clip(self): + """Handles the modification and reloading of the selected clip.""" + self._generate_html() + self._generate_clip(self.clip.get_uri()[7:]) + self.clip.get_asset().set_meta("pitivi::clip_content", self.text_entered) + self.clip.get_asset().set_meta("pitivi::clip_type", self.clip_name) + GES.Asset.needs_reload(GES.UriClip, self.clip.get_asset().props.id) + self.clip = None + + def _generate_html(self): + """Reads the template.txt, modifies its content and write it to a HTML file that is used to generate clip.""" + with open("data/closing_credits/template.txt", "r", encoding="utf-8") as file: + template_content = file.read() + template_content = template_content.format(type=self.clip_name, content=self.text_entered) + with open("data/closing_credits/closingcredits.html", "w", encoding="utf-8") as html_file: + html_file.write(template_content) + + def _generate_clip(self, output_clip_path): + """Generate clip using wpe package taking HTML as input and stores it in output_clip_path location.""" + file_uri = Gst.filename_to_uri(os.getcwd() + "/data/closing_credits/closingcredits.html") + pipe = Gst.Pipeline() + pipe = Gst.parse_launch("wpevideosrc num-buffers=200 location=" + file_uri + " draw-background=0 ! video/x-raw,framerate=30/1 ! videoconvert ! x264enc ! mp4mux ! filesink location=" + output_clip_path) + pipe.set_state(Gst.State.PLAYING) + bus = pipe.get_bus() + msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) + if msg.type == Gst.MessageType.ERROR: + err, debug = msg.parse_error() + self.log("Error received from element %s: %s" % (msg.src.get_name(), err)) + self.log("Debugging information: %s" % debug) + elif msg.type == Gst.MessageType.EOS: + self.log("End-Of-Stream reached.") + else: + self.log("Unexpected message received.") + pipe.set_state(Gst.State.NULL) diff --git a/pitivi/editorperspective.py b/pitivi/editorperspective.py index 40aafe18a..f3dc74206 100644 --- a/pitivi/editorperspective.py +++ b/pitivi/editorperspective.py @@ -36,7 +36,6 @@ from pitivi.mediafilespreviewer import PreviewWidget from pitivi.medialibrary import MediaLibraryWidget from pitivi.perspective import Perspective from pitivi.settings import GlobalSettings -from pitivi.specialclips import SpecialClipWidget from pitivi.tabsmanager import BaseTabs from pitivi.timeline.previewers import ThumbnailCache from pitivi.timeline.timeline import TimelineContainer @@ -210,17 +209,13 @@ class EditorPerspective(Perspective, Loggable): self.main_tabs = BaseTabs(self.app) self.medialibrary = MediaLibraryWidget(self.app) self.effectlist = EffectListWidget(self.app) - self.specialcliplist = SpecialClipWidget(self.app) self.main_tabs.append_page("Media Library", self.medialibrary, Gtk.Label.new(_("Media Library"))) self.main_tabs.append_page("Effect Library", self.effectlist, Gtk.Label.new(_("Effect Library"))) - self.main_tabs.append_page("Special Clips", - self.specialcliplist, Gtk.Label.new(_("Special Clips"))) self.medialibrary.connect('play', self._media_library_play_cb) self.medialibrary.show() self.effectlist.show() - self.specialcliplist.show() # Second set of tabs self.context_tabs = BaseTabs(self.app) diff --git a/pitivi/specialclips.py b/pitivi/specialclips.py deleted file mode 100644 index f42e7bba6..000000000 --- a/pitivi/specialclips.py +++ /dev/null @@ -1,303 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2023, Rhythm Narula -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, see . -"""Classes for handling Special Clips.""" -import os - -from gi.repository import GES -from gi.repository import GLib -from gi.repository import Gst -from gi.repository import Gtk - -from pitivi.configure import get_ui_dir -from pitivi.utils.loggable import Loggable -from pitivi.utils.ui import get_widget_children -from pitivi.utils.ui import SPACING - -SPECIAL_CLIPS_INFO = { - 'Closing Credit Clip': [ - ['Center', 'Place the content at center'], - ['Right', 'Place the content at the right'], - ['Left', 'Place the content at the left'], - ], - 'Audio Clip': [ - ['Jingle Bell', 'Play Jingle bell sound'], - ] -} - -ICON_WIDTH = 80 -ICON_HEIGHT = 45 - - -class ClipInfo: - """Info for displaying and using a special clip. - - Attributes: - clip_name (str): Used for identifying the clip type, example - closing_credit_clip. - clip_category (str): Used for identifying further category, example - Center, Left or Right. - clip_description (str): Used for describing the effect. - """ - - def __init__(self, clip_name, clip_category, clip_description): - self.clip_name = clip_name - self.clip_category = clip_category - self.clip_description = clip_description - - -class SpecialClipManager(Loggable): - """Keeps info about effects and their categories. - - Attributes: - SPECIAL_CLIPS_INFO : The available effects. - """ - - def __init__(self): - Loggable.__init__(self) - self._special_clips = {} - for clip_type in SPECIAL_CLIPS_INFO.items(): - clips = clip_type[1] - for clip in clips: - clip_info = ClipInfo(clip[0], clip_type[0], clip[1]) - self._special_clips[clip[0]] = clip_info - - -class SpecialClipWidget(Gtk.Box, Loggable): - """Widget for managing special clips. - - Attributes: - app (Pitivi): The app. - """ - - def __init__(self, app): - Gtk.Box.__init__(self) - Loggable.__init__(self) - - self.app = app - self.set_orientation(Gtk.Orientation.VERTICAL) - builder = Gtk.Builder(self) - builder.add_from_file(os.path.join(get_ui_dir(), "specialcliplibrary.ui")) - toolbar = builder.get_object("specialcliplibrary_box") - self.search_entry = builder.get_object("search_entry") - - self.main_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - - self.category_view = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - self.category_view.set_hexpand(True) - self.category_view.set_halign(Gtk.Align.FILL) - self.main_view.prepend(self.category_view) - - scrollwin = Gtk.ScrolledWindow() - scrollwin.props.hscrollbar_policy = Gtk.PolicyType.NEVER - scrollwin.props.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC - scrollwin.set_vexpand(True) - scrollwin.set_valign(Gtk.Align.FILL) - scrollwin.set_child(self.main_view) - - self.prepend(toolbar) - self.prepend(scrollwin) - - GLib.idle_add(self._load_available_clips_cb) - - def _load_available_clips_cb(self): - self._set_up_category_view() - - def _set_up_category_view(self): - """Adds expanders and clip types to the category view.""" - for category in SPECIAL_CLIPS_INFO: - widget = self._create_category_widget(category) - self.category_view.append(widget) - - for expander in get_widget_children(self.category_view): - listbox = expander.get_child() - category_name = expander.get_label() - self._add_effects_to_listbox(listbox, category_name) - - self.category_view.show() - - def _create_category_widget(self, category): - """Creates an expander for the given category.""" - expander = Gtk.Expander( - label=category, - margin_top=SPACING, - margin_bottom=SPACING, - margin_start=SPACING, - margin_end=SPACING - ) - - listbox = Gtk.ListBox(activate_on_single_click=False) - listbox.connect("row-activated", self._effects_listbox_row_activated_cb) - expander.set_child(listbox) - return expander - - def _effects_listbox_row_activated_cb(self, listbox, row): - """Handles the activation of a row representing a clip.""" - effect_box = row.get_first_child() - dialog = SpecialClipSettingsDialog(self.app.gui, self.app, effect_box.clip_name, None) - dialog.window.set_modal(True) - dialog.window.show() - - def _add_effects_to_listbox(self, listbox, category=None): - """Adds effect rows to the given listbox.""" - for clips in SPECIAL_CLIPS_INFO[category]: - widget = self._create_effect_widget(clips[0], clips[1]) - listbox.insert(widget, -1) - - def _create_effect_widget(self, clip_name, clip_description): - clip_box = Gtk.Box( - orientation=Gtk.Orientation.HORIZONTAL, - margin_top=SPACING / 2, - margin_bottom=SPACING / 2, - margin_start=SPACING / 2, - margin_end=SPACING / 2 - ) - clip_box.clip_name = clip_name - clip_box.set_tooltip_text(clip_description) - label = Gtk.Label.new(clip_name) - label.set_xalign(0) - label.set_halign(Gtk.Align.FILL) - label.set_hexpand(True) - - clip_box.prepend(label) - row = Gtk.ListBoxRow(selectable=False) - row.set_child(clip_box) - return row - - -class SpecialClipSettingsDialog: - """Manager of a dialog for viewing and changing the special clip settings. - - Attributes: - parent_window : Window from which this widget is called. - app (Pitivi): The current app. - clip_name : Type of the clip, example - center, right or left. - clip : Clip to be modified. - """ - - def __init__(self, parent_window, app, clip_name, clip): - self.app = app - self.project = self.app.project_manager.current_project - - self.proxy_aspect_ratio = Gst.Fraction(1, 0) - - self.text_entered = "" - self.placeholder_str = """

Directed By

-

Rhythm Narula

-

Screenplay By

-

Alan Silvestri

-

Produced By

-

Joanna Johnston

-

Director of Photography

-

Ken Ralston

-

Digital Artist

-

Thibault Saunier

-

Musicians

-

Rhythm Narula

-

Digital Artist

-

Alexandru Băluț

-

Costumes Designed By

-

Andy Guthenberg/p> -

Co-Producers

-

Rhythm Narula

-

-

Additional Visual Effects by WETA, LTD

-

Wellington, New Zealand

-

-

First-Assistant Camera - Tony Rivetti

-

Second-Assistant Camera - Frank D. Parish

-

Aerial Coordinator - Kevin La Rosa

-

-

Visual Effects Supervisor- Stephen Rosenbaum

-
-

Filmed in PANAVISION

-

Color and prints by TECHNICOLOR

-

Kodak Motion Picture Products

- """ - self.clip_name = clip_name - self.clip = clip - self._create_ui() - self.window.set_transient_for(parent_window) - - def _create_ui(self): - """Creates UI of the Text Editor to enter content to be displayed on clip.""" - self.builder = Gtk.Builder(self) - self.builder.add_from_file( - os.path.join(get_ui_dir(), "specialclipdialog.ui")) - self.window = self.builder.get_object("specialclip-settings-dialog") - self.window.set_size_request(600, 700) - - self.text_entry = self.builder.get_object("text_entry") - self.textbuf = self.builder.get_object("textview1").get_buffer() - self.textbuf.set_text(self.placeholder_str) - - def _response_cb(self, unused_widget, response): - """Handles the dialog being closed.""" - if response == Gtk.ResponseType.OK: - self._update_details() - self.window.destroy() - - def _update_details(self): - """Updates text entered and handles the generation/modification of clip.""" - self.text_entered = self.textbuf.get_text(self.textbuf.get_start_iter(), self.textbuf.get_end_iter(), True) - if self.clip is None: - self._generate_closing_credit_clip() - else: - self._update_closing_credit_clip() - - def _generate_closing_credit_clip(self): - """Handles the generation and addition of generated closing credit clip to project.""" - self._generate_html() - self._generate_clip("output.mp4") - filenames = [os.getcwd() + "/output.mp4"] - self.project.add_uris(filenames) - assets = GES.list_assets(GES.UriClip) - for asset in assets: - if os.path.basename(asset.get_id()) == 'output.mp4': - asset.set_meta("pitivi::tags", "closing_credit") - - def _update_closing_credit_clip(self): - """Handles the modification and reloading of the selected clip.""" - self._generate_html() - self._generate_clip(self.clip.get_uri()[7:]) - GES.Asset.needs_reload(GES.UriClip, self.clip.get_asset().props.id) - self.clip = None - - def _generate_html(self): - """Modifies the HTML with the entered text and type to be used to generate clip.""" - with open("data/closing_credits/template.html", "r", encoding="utf-8") as file: - template_content = file.read() - - template_content = template_content.replace("{{clip_content}}", self.text_entered) - template_content = template_content.replace("Center", self.clip_name) - - with open("data/closing_credits/template.html", "w", encoding="utf-8") as html_file: - html_file.write(template_content) - - def _generate_clip(self, output_clip_path): - """Generate clip using wpe package taking HTML as input and stores it in output_clip_path location.""" - file_uri = Gst.filename_to_uri(os.getcwd() + "/data/closing_credits/template.html") - pipe = Gst.Pipeline() - pipe = Gst.parse_launch("wpevideosrc num-buffers=200 location=" + file_uri + " draw-background=0 ! video/x-raw,framerate=30/1 ! videoconvert ! x264enc ! mp4mux ! filesink location=" + output_clip_path) - pipe.set_state(Gst.State.PLAYING) - bus = pipe.get_bus() - msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) - if msg.type == Gst.MessageType.ERROR: - err, debug = msg.parse_error() - print("Error received from element %s: %s" % (msg.src.get_name(), err)) - print("Debugging information: %s" % debug) - elif msg.type == Gst.MessageType.EOS: - print("End-Of-Stream reached.") - else: - print("Unexpected message received.") - pipe.set_state(Gst.State.NULL) diff --git a/pitivi/utils/misc.py b/pitivi/utils/misc.py index c663b43cc..cec8df613 100644 --- a/pitivi/utils/misc.py +++ b/pitivi/utils/misc.py @@ -420,7 +420,7 @@ def _get_square_width(video_info): def video_info_get_rotation(video_info): tags = video_info.get_tags() - if not tags: + if tags is None: return 0 is_rotated, rotation_string = tags.get_string(Gst.TAG_IMAGE_ORIENTATION) -- GitLab