[pitivi] layer: Toggle layer visibility
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] layer: Toggle layer visibility
- Date: Mon, 27 Apr 2020 11:03:22 +0000 (UTC)
commit 9168854962b7f61c94ad5bd0d5d8c1ff56d695e3
Author: Vivek R <123vivekr gmail com>
Date: Sun Apr 5 22:52:23 2020 +0530
layer: Toggle layer visibility
Closes #2422
data/pixmaps/eye-not-looking-symbolic.svg | 3 +
data/pixmaps/eye-open-negative-filled-symbolic.svg | 65 +++++++++++++++++++
pitivi/timeline/layer.py | 70 +++++++++++++++-----
tests/test_timeline_layer.py | 75 ++++++++++++++++++----
4 files changed, 185 insertions(+), 28 deletions(-)
---
diff --git a/data/pixmaps/eye-not-looking-symbolic.svg b/data/pixmaps/eye-not-looking-symbolic.svg
new file mode 100644
index 00000000..ad75f422
--- /dev/null
+++ b/data/pixmaps/eye-not-looking-symbolic.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+ <path d="M13.98 1.99a1 1 0 0 0-.687.303l-.984.984A8 8 0 0 0 8 2 8 8 0 0 0 .262 8.01a8 8 0 0 0 2.943
4.37l-.912.913a1 1 0 1 0 1.414 1.414l11-11a1 1 0 0 0-.727-1.717zM8 4a4 4 0 0 1 2.611.974l-1.42 1.42A2 2 0 0 0
8 6a2 2 0 0 0-2 2 2 2 0 0 0 .396 1.19l-1.42 1.42A4 4 0 0 1 4 8a4 4 0 0 1 4-4zm7.03 2.209l-3.344 3.343a4 4 0 0
1-2.127 2.127l-2.28 2.28a8 8 0 0 0 .721.04 8 8 0 0 0 7.738-6.01 8 8 0 0 0-.709-1.78zm-7.53.79a.5.5 0 0 1
.5.5.5.5 0 0 1-.5.5.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5z" fill="#2e3436"/>
+</svg>
diff --git a/data/pixmaps/eye-open-negative-filled-symbolic.svg
b/data/pixmaps/eye-open-negative-filled-symbolic.svg
new file mode 100644
index 00000000..dc8b5d00
--- /dev/null
+++ b/data/pixmaps/eye-open-negative-filled-symbolic.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ width="16"
+ viewBox="0 0 16 16"
+ version="1.1"
+ id="svg7384"
+ height="16">
+ <metadata
+ id="metadata90">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Gnome Symbolic Icon Theme</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <title
+ id="title9167">Gnome Symbolic Icon Theme</title>
+ <defs
+ id="defs7386">
+ <linearGradient
+ osb:paint="solid"
+ id="linearGradient7212">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop7214" />
+ </linearGradient>
+ </defs>
+ <g
+ transform="translate(-341.0002,-13.000323)"
+ style="display:inline"
+ id="layer9" />
+ <g
+ transform="translate(-100,-380.00032)"
+ id="layer1" />
+ <g
+ transform="translate(-100,-380.00032)"
+ style="display:inline"
+ id="layer10">
+ <path
+ d="m 108,382 a 8,8 0 0 0 -7.73828,6.00977 A 8,8 0 0 0 108,394 8,8 0 0 0 115.73828,387.99023 8,8 0 0 0
108,382 Z m 0,2 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z"
+ id="path2314"
+
style="opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
/>
+ <path
+ id="path2318"
+ d="m 110,388.00003 a 2,2 0 0 1 -2,2 2,2 0 0 1 -2,-2 2,2 0 0 1 2,-2 2,2 0 0 1 2,2 z"
+
style="vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
/>
+ </g>
+ <g
+ transform="translate(-100,-380.00032)"
+ id="g6387" />
+ <g
+ transform="translate(-100,-380.00032)"
+ id="layer11" />
+</svg>
diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py
index d8e2658e..2e5b2124 100644
--- a/pitivi/timeline/layer.py
+++ b/pitivi/timeline/layer.py
@@ -31,6 +31,17 @@ from pitivi.utils.ui import PADDING
from pitivi.utils.ui import SEPARATOR_HEIGHT
+AUDIO_ICONS = {
+ True: "audio-volume-high-symbolic",
+ False: "audio-volume-muted-symbolic",
+}
+
+VIDEO_ICONS = {
+ True: "eye-open-negative-filled-symbolic",
+ False: "eye-not-looking-symbolic",
+}
+
+
class SpacedSeparator(Gtk.EventBox):
"""A Separator with vertical spacing.
@@ -60,6 +71,7 @@ class LayerControls(Gtk.EventBox, Loggable):
tracks = self.ges_timeline.get_tracks()
self.timeline_audio_tracks = [track for track in tracks if track.props.track_type ==
GES.TrackType.AUDIO]
+ self.timeline_video_tracks = [track for track in tracks if track.props.track_type ==
GES.TrackType.VIDEO]
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
self.add(hbox)
@@ -86,12 +98,19 @@ class LayerControls(Gtk.EventBox, Loggable):
self.__update_name()
name_row.pack_start(self.name_entry, True, True, 0)
- self.mute_toggle_button = Gtk.ToggleButton.new()
- self.mute_toggle_button.props.valign = Gtk.Align.CENTER
- self.mute_toggle_button.props.relief = Gtk.ReliefStyle.NONE
- self.mute_toggle_button.connect("toggled", self.__mute_button_toggled_cb)
- self.__update_mute_button()
- name_row.pack_start(self.mute_toggle_button, False, False, 0)
+ self.audio_button = Gtk.Button.new()
+ self.audio_button.connect("clicked", self.__audio_button_clicked_cb)
+ self.__update_audio_button()
+
+ self.video_button = Gtk.Button.new()
+ 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.add(self.video_button)
+ control_box.add(self.audio_button)
+ name_row.pack_start(control_box, False, False, 0)
self.menubutton = Gtk.MenuButton.new()
self.menubutton.props.valign = Gtk.Align.CENTER
@@ -224,24 +243,43 @@ class LayerControls(Gtk.EventBox, Loggable):
self.ges_timeline.ui.move_layer(self.ges_layer, index)
self.app.project_manager.current_project.pipeline.commit_timeline()
- def __mute_button_toggled_cb(self, button):
- self.ges_layer.set_active_for_tracks(not button.get_active(), self.timeline_audio_tracks)
+ def __audio_button_clicked_cb(self, button):
+ self.ges_layer.set_active_for_tracks(not self.__check_tracks_active(
+ self.timeline_audio_tracks), self.timeline_audio_tracks)
self.app.project_manager.current_project.pipeline.commit_timeline()
- def __update_mute_button(self):
- muted = all([not self.ges_layer.get_active_for_track(t) for t in self.timeline_audio_tracks])
- self.mute_toggle_button.set_active(muted)
- icon_name = "audio-volume-muted-symbolic" if muted else "audio-volume-high-symbolic"
- image = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.BUTTON)
- self.mute_toggle_button.set_image(image)
+ def __update_audio_button(self):
+ active = self.__check_tracks_active(self.timeline_audio_tracks)
+ icon = AUDIO_ICONS[active]
+ self.audio_button.set_image(Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON))
+
+ def __video_button_clicked_cb(self, button):
+ self.ges_layer.set_active_for_tracks(not self.__check_tracks_active(
+ self.timeline_video_tracks), self.timeline_video_tracks)
+ self.app.project_manager.current_project.pipeline.commit_timeline()
+
+ def __update_video_button(self):
+ active = self.__check_tracks_active(self.timeline_video_tracks)
+ icon = VIDEO_ICONS[active]
+ self.video_button.set_image(Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON))
def __layer_active_changed_cb(self, ges_layer, active, tracks):
- self.__update_mute_button()
+ self.__update_video_button()
+ self.__update_audio_button()
+
+ def __check_tracks_active(self, tracks):
+ return all([self.ges_layer.get_active_for_track(t) for t in tracks])
def update(self, media_types):
self.props.height_request = self.ges_layer.ui.props.height_request
- if media_types & GES.TrackType.VIDEO or not media_types:
+ has_audio = media_types & GES.TrackType.AUDIO
+ self.audio_button.set_sensitive(has_audio)
+
+ has_video = media_types & GES.TrackType.VIDEO
+ self.video_button.set_sensitive(has_video)
+
+ if has_video or not media_types:
# The layer has video or is empty.
icon = "video-x-generic-symbolic"
else:
diff --git a/tests/test_timeline_layer.py b/tests/test_timeline_layer.py
index fa0bcf24..752ab88f 100644
--- a/tests/test_timeline_layer.py
+++ b/tests/test_timeline_layer.py
@@ -18,7 +18,9 @@ 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 VIDEO_ICONS
from tests import common
@@ -46,50 +48,99 @@ class TestLayerControl(common.TestCase):
layer.set_name("Layer 0x")
self.assertEqual(layer.get_name(), "Layer 0x")
- def test_mute_and_unmute_layer(self):
+ def test_audio_toggle(self):
+ """Checks that audio toggling is reflected in the UI."""
timeline_container = common.create_timeline_container()
timeline = timeline_container.timeline
ges_layer = timeline.ges_timeline.append_layer()
layer_controls = ges_layer.control_ui
- mute_toggle_button = layer_controls.mute_toggle_button
+ audio_button = layer_controls.audio_button
for audio_track in layer_controls.timeline_audio_tracks:
self.assertTrue(ges_layer.get_active_for_track(audio_track))
- self.assertFalse(mute_toggle_button.get_active())
+ self.assertEqual(audio_button.get_image().props.icon_name, AUDIO_ICONS[True])
ges_layer.set_active_for_tracks(False, [audio_track])
common.create_main_loop().run(until_empty=True)
self.assertFalse(ges_layer.get_active_for_track(audio_track))
- self.assertTrue(mute_toggle_button.get_active())
+ self.assertEqual(audio_button.get_image().props.icon_name, AUDIO_ICONS[False])
ges_layer.set_active_for_tracks(True, [audio_track])
common.create_main_loop().run(until_empty=True)
self.assertTrue(ges_layer.get_active_for_track(audio_track))
- self.assertFalse(mute_toggle_button.get_active())
+ self.assertEqual(audio_button.get_image().props.icon_name, AUDIO_ICONS[True])
- def test_mute_and_unmute_layer_button(self):
+ def test_audio_button(self):
+ """Checks that the audio button toggles the audio track."""
timeline_container = common.create_timeline_container()
timeline = timeline_container.timeline
ges_layer = timeline.ges_timeline.append_layer()
layer_controls = ges_layer.control_ui
- mute_toggle_button = layer_controls.mute_toggle_button
+ audio_button = layer_controls.audio_button
for audio_track in layer_controls.timeline_audio_tracks:
self.assertTrue(ges_layer.get_active_for_track(audio_track))
common.create_main_loop().run(until_empty=True)
- self.assertFalse(mute_toggle_button.get_active())
+ self.assertEqual(audio_button.get_image().props.icon_name, AUDIO_ICONS[True])
- mute_toggle_button.clicked()
+ audio_button.clicked()
for audio_track in layer_controls.timeline_audio_tracks:
self.assertFalse(ges_layer.get_active_for_track(audio_track))
common.create_main_loop().run(until_empty=True)
- self.assertTrue(mute_toggle_button.get_active())
+ self.assertEqual(audio_button.get_image().props.icon_name, AUDIO_ICONS[False])
- mute_toggle_button.clicked()
+ audio_button.clicked()
for audio_track in layer_controls.timeline_audio_tracks:
self.assertTrue(ges_layer.get_active_for_track(audio_track))
common.create_main_loop().run(until_empty=True)
- self.assertFalse(mute_toggle_button.get_active())
+ self.assertEqual(audio_button.get_image().props.icon_name, AUDIO_ICONS[True])
+
+ def test_video_toggle(self):
+ """Checks that video toggling is reflected in the UI."""
+ timeline_container = common.create_timeline_container()
+ timeline = timeline_container.timeline
+ ges_layer = timeline.ges_timeline.append_layer()
+ layer_controls = ges_layer.control_ui
+ video_button = layer_controls.video_button
+
+ for video_track in layer_controls.timeline_video_tracks:
+ self.assertTrue(ges_layer.get_active_for_track(video_track))
+ self.assertEqual(video_button.get_image().props.icon_name, VIDEO_ICONS[True])
+
+ ges_layer.set_active_for_tracks(False, [video_track])
+ common.create_main_loop().run(until_empty=True)
+ self.assertFalse(ges_layer.get_active_for_track(video_track))
+ self.assertEqual(video_button.get_image().props.icon_name, VIDEO_ICONS[False])
+
+ ges_layer.set_active_for_tracks(True, [video_track])
+ common.create_main_loop().run(until_empty=True)
+ self.assertTrue(ges_layer.get_active_for_track(video_track))
+ self.assertEqual(video_button.get_image().props.icon_name, VIDEO_ICONS[True])
+
+ def test_video_button(self):
+ """Checks that the video button toggles the video track."""
+ timeline_container = common.create_timeline_container()
+ timeline = timeline_container.timeline
+ ges_layer = timeline.ges_timeline.append_layer()
+ layer_controls = ges_layer.control_ui
+ video_button = layer_controls.video_button
+
+ for video_track in layer_controls.timeline_video_tracks:
+ self.assertTrue(ges_layer.get_active_for_track(video_track))
+ common.create_main_loop().run(until_empty=True)
+ self.assertEqual(video_button.get_image().props.icon_name, VIDEO_ICONS[True])
+
+ video_button.clicked()
+ for video_track in layer_controls.timeline_video_tracks:
+ self.assertFalse(ges_layer.get_active_for_track(video_track))
+ common.create_main_loop().run(until_empty=True)
+ self.assertEqual(video_button.get_image().props.icon_name, VIDEO_ICONS[False])
+
+ video_button.clicked()
+ for video_track in layer_controls.timeline_video_tracks:
+ self.assertTrue(ges_layer.get_active_for_track(video_track))
+ common.create_main_loop().run(until_empty=True)
+ self.assertEqual(video_button.get_image().props.icon_name, VIDEO_ICONS[True])
class TestLayer(common.TestCase):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]