[gnome-music/wip/mschraal/artrework: 13/15] Add CoverStack for smooth art transitions
- From: Marinus Schraal <mschraal src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/mschraal/artrework: 13/15] Add CoverStack for smooth art transitions
- Date: Mon, 5 Feb 2018 12:59:26 +0000 (UTC)
commit 0cd7131dd222483cec34668da8cc45f22bc73f5e
Author: Marinus Schraal <mschraal gnome org>
Date: Mon Jan 29 09:56:31 2018 +0100
Add CoverStack for smooth art transitions
Adds a Gtk.Stack based widget that provides a smooth transition between
image states.
Closes: #55
data/AlbumCover.ui | 2 +-
data/ArtistAlbumWidget.ui | 2 +-
data/PlayerToolbar.ui | 2 +-
gnomemusic/player.py | 10 ++--
gnomemusic/views/albumsview.py | 9 ++--
gnomemusic/widgets/Makefile.am | 1 +
gnomemusic/widgets/artistalbumswidget.py | 2 +-
gnomemusic/widgets/artistalbumwidget.py | 10 ++--
gnomemusic/widgets/coverstack.py | 87 ++++++++++++++++++++++++++++++++
9 files changed, 109 insertions(+), 16 deletions(-)
---
diff --git a/data/AlbumCover.ui b/data/AlbumCover.ui
index 4309a3d..39a79d2 100644
--- a/data/AlbumCover.ui
+++ b/data/AlbumCover.ui
@@ -16,7 +16,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkImage" id="image">
+ <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vexpand">True</property>
diff --git a/data/ArtistAlbumWidget.ui b/data/ArtistAlbumWidget.ui
index a0460ee..ae71f14 100644
--- a/data/ArtistAlbumWidget.ui
+++ b/data/ArtistAlbumWidget.ui
@@ -6,7 +6,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkImage" id="cover">
+ <object class="GtkStack" id="cover">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
diff --git a/data/PlayerToolbar.ui b/data/PlayerToolbar.ui
index 53028c6..f42f256 100644
--- a/data/PlayerToolbar.ui
+++ b/data/PlayerToolbar.ui
@@ -122,7 +122,7 @@
<property name="valign">center</property>
<property name="spacing">8</property>
<child>
- <object class="GtkImage" id="cover">
+ <object class="GtkStack" id="cover">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 6a5a800..75e62e1 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -46,10 +46,11 @@ from gi.repository import Gtk, GLib, Gio, GObject, Gst, GstAudio, GstPbutils
from gettext import gettext as _, ngettext
from gnomemusic import log
-from gnomemusic.albumartcache import Art, ArtImage
+from gnomemusic.albumartcache import Art
from gnomemusic.grilo import grilo
from gnomemusic.playlists import Playlists
from gnomemusic.scrobbler import LastFmScrobbler
+from gnomemusic.widgets.coverstack import CoverStack
import gnomemusic.utils as utils
@@ -579,8 +580,7 @@ class Player(GObject.GObject):
artist = utils.get_artist_name(media)
self.artistLabel.set_label(artist)
- art = ArtImage(Art.Size.XSMALL, media)
- art.image = self._image
+ self._cover_stack.update(media)
title = utils.get_media_title(media)
self.titleLabel.set_label(title)
@@ -775,7 +775,9 @@ class Player(GObject.GObject):
self.songTotalTimeLabel = self._ui.get_object('duration')
self.titleLabel = self._ui.get_object('title')
self.artistLabel = self._ui.get_object('artist')
- self._image = self._ui.get_object('cover')
+
+ stack = self._ui.get_object('cover')
+ self._cover_stack = CoverStack(stack, Art.Size.XSMALL)
self.duration = self._ui.get_object('duration')
self.repeatBtnImage = self._ui.get_object('playlistRepeat')
diff --git a/gnomemusic/views/albumsview.py b/gnomemusic/views/albumsview.py
index b214859..8fef4f0 100644
--- a/gnomemusic/views/albumsview.py
+++ b/gnomemusic/views/albumsview.py
@@ -26,11 +26,12 @@ from gettext import gettext as _
from gi.repository import GLib, GObject, Gtk, Gdk
from gnomemusic import log
-from gnomemusic.albumartcache import Art, ArtImage
+from gnomemusic.albumartcache import Art
from gnomemusic.grilo import grilo
from gnomemusic.toolbar import ToolbarState
from gnomemusic.views.baseview import BaseView
from gnomemusic.widgets.albumwidget import AlbumWidget
+from gnomemusic.widgets.coverstack import CoverStack
import gnomemusic.utils as utils
@@ -157,7 +158,7 @@ class AlbumsView(BaseView):
'/org/gnome/Music/AlbumCover.ui')
child = Gtk.FlowBoxChild()
- child.image = builder.get_object('image')
+ child.stack = builder.get_object('stack')
child.check = builder.get_object('check')
child.title = builder.get_object('title')
child.subtitle = builder.get_object('subtitle')
@@ -183,8 +184,8 @@ class AlbumsView(BaseView):
child.add(builder.get_object('main_box'))
child.show()
- art = ArtImage(Art.Size.MEDIUM, item)
- art.image = child.image
+ cover_stack = CoverStack(child.stack, Art.Size.MEDIUM)
+ cover_stack.update(item)
return child
diff --git a/gnomemusic/widgets/Makefile.am b/gnomemusic/widgets/Makefile.am
index 3b50455..69b259c 100644
--- a/gnomemusic/widgets/Makefile.am
+++ b/gnomemusic/widgets/Makefile.am
@@ -5,6 +5,7 @@ app_PYTHON = \
albumwidget.py \
artistalbumswidget.py \
artistalbumwidget.py \
+ coverstack.py \
disclistboxwidget.py \
notificationspopup.py \
playlistdialog.py \
diff --git a/gnomemusic/widgets/artistalbumswidget.py b/gnomemusic/widgets/artistalbumswidget.py
index 21a45d8..ca5a0b6 100644
--- a/gnomemusic/widgets/artistalbumswidget.py
+++ b/gnomemusic/widgets/artistalbumswidget.py
@@ -124,7 +124,7 @@ class ArtistAlbumsWidget(Gtk.Box):
self._selection_mode_allowed,
self._songs_grid_size_group,
self._cover_size_group)
- self._cover_size_group.add_widget(widget.cover)
+ self._cover_size_group.add_widget(widget.cover_stack._stack)
self._album_box.pack_start(widget, False, False, 0)
self._widgets.append(widget)
diff --git a/gnomemusic/widgets/artistalbumwidget.py b/gnomemusic/widgets/artistalbumwidget.py
index a86eca2..c26af1e 100644
--- a/gnomemusic/widgets/artistalbumwidget.py
+++ b/gnomemusic/widgets/artistalbumwidget.py
@@ -25,8 +25,9 @@
from gi.repository import GObject, Gtk
from gnomemusic import log
-from gnomemusic.albumartcache import Art, ArtImage
+from gnomemusic.albumartcache import Art
from gnomemusic.grilo import grilo
+from gnomemusic.widgets.coverstack import CoverStack
from gnomemusic.widgets.disclistboxwidget import DiscBox
import gnomemusic.utils as utils
@@ -67,8 +68,9 @@ class ArtistAlbumWidget(Gtk.Box):
ui.add_from_resource('/org/gnome/Music/ArtistAlbumWidget.ui')
self.cover = ui.get_object('cover')
- art = ArtImage(Art.Size.MEDIUM, self._media)
- art.image = self.cover
+
+ self.cover_stack = CoverStack(self.cover, Art.Size.MEDIUM)
+ self.cover_stack.update(self._media)
self._disc_listbox = ui.get_object('disclistbox')
self._disc_listbox.set_selection_mode_allowed(
@@ -85,7 +87,7 @@ class ArtistAlbumWidget(Gtk.Box):
self._size_group.add_widget(ui.get_object('box1'))
if self._cover_size_group:
- self._cover_size_group.add_widget(self.cover)
+ self._cover_size_group.add_widget(self.cover_stack._stack)
self.pack_start(ui.get_object('ArtistAlbumWidget'), True, True, 0)
diff --git a/gnomemusic/widgets/coverstack.py b/gnomemusic/widgets/coverstack.py
new file mode 100644
index 0000000..c5f623f
--- /dev/null
+++ b/gnomemusic/widgets/coverstack.py
@@ -0,0 +1,87 @@
+# Copyright © 2018 The GNOME Music developers
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music. This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered. If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version.
+
+from gi.repository import GObject, Gtk
+
+from gnomemusic import log
+from gnomemusic.albumartcache import Art, DefaultIcon
+
+
+class CoverStack(GObject.GObject):
+ """Provides a smooth transition between image states
+
+ Uses a Gtk.Stack to provide an in-situ transition between an image
+ state. Either between the 'loading' state versus the 'loaded' state
+ or in between songs.
+ """
+
+ _default_icon = DefaultIcon()
+
+ @log
+ def __init__(self, stack, size):
+ super().__init__()
+
+ self._size = size
+ self._stack = stack
+ self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
+ self._scale = self._stack.get_scale_factor()
+ self._handler_id = None
+
+ self._loading_icon = self._default_icon.get(
+ DefaultIcon.Type.LOADING, self._size, self._scale)
+
+ self._loading_cover = Gtk.Image.new_from_surface(self._loading_icon)
+
+ self._cover_a = Gtk.Image()
+ self._cover_b = Gtk.Image()
+
+ self._stack.add_named(self._loading_cover, "loading")
+ self._stack.add_named(self._cover_a, "A")
+ self._stack.add_named(self._cover_b, "B")
+
+ self._stack.set_visible_child_name("loading")
+ self._stack.show_all()
+
+ @log
+ def update(self, media):
+ """Update the stack with the given media
+
+ Update the stack with the art retrieved from the given media.
+ :param Grl.Media media: The media object
+ """
+ self._active_child = self._stack.get_visible_child_name()
+
+ art = Art(self._size, media, self._scale)
+ self._handler_id = art.connect('finished', self._art_retrieved)
+ art.lookup()
+
+ @log
+ def _art_retrieved(self, klass):
+ klass.disconnect(self._handler_id)
+ if self._active_child == "B":
+ self._cover_a.set_from_surface(klass.surface)
+ self._stack.set_visible_child_name("A")
+ else:
+ self._cover_b.set_from_surface(klass.surface)
+ self._stack.set_visible_child_name("B")
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]