def __init__(self, player, parent_view): """Initialize the AlbumWidget. :param player: The player object :param parent_view: The view this widget is part of """ Gtk.EventBox.__init__(self) self._songs = [] scale = self.get_scale_factor() self._cache = AlbumArtCache(scale) self._loading_icon_surface = DefaultIcon(scale).get( DefaultIcon.Type.loading, ArtSize.large) self._player = player self._iter_to_clean = None self._selection_mode = False self._builder = Gtk.Builder() self._builder.add_from_resource('/org/gnome/Music/AlbumWidget.ui') self._create_model() self._album = None self._header_bar = None self._selection_mode_allowed = True self._composer_label = self._builder.get_object('composer_label') self._composer_info = self._builder.get_object('composer_info') view_box = self._builder.get_object('view') self._disc_listbox = DiscListBox() self._disc_listbox.set_selection_mode_allowed(True) # TODO: The top of the coverart is the same vertical # position as the top of the album songs, however # since we set a top margins for the discbox # subtract that margin here. A cleaner solution is # appreciated. self._disc_listbox.set_margin_top(64 - 16) self._disc_listbox.set_margin_bottom(64) self._disc_listbox.set_margin_end(32) self._disc_listbox.connect('selection-changed', self._on_selection_changed) view_box.add(self._disc_listbox) # FIXME: Assigned to appease searchview # _get_selected_songs self.view = self._disc_listbox self.add(self._builder.get_object('AlbumWidget')) self.get_style_context().add_class('view') self.get_style_context().add_class('content-view') self.show_all()
def __init__(self, player, parent_view): """Initialize the AlbumWidget. :param player: The player object :param parent_view: The view this widget is part of """ Gtk.EventBox.__init__(self) self._tracks = [] scale = self.get_scale_factor() self._cache = AlbumArtCache(scale) self._loading_icon_surface = DefaultIcon(scale).get(DefaultIcon.Type.loading, ArtSize.large) self._player = player self._iter_to_clean = None self._selection_mode = False self._builder = Gtk.Builder() self._builder.add_from_resource("/org/gnome/Music/AlbumWidget.ui") self._create_model() self._album = None self._header_bar = None self._selection_mode_allowed = True self._composer_label = self._builder.get_object("composer_label") self._composer_info = self._builder.get_object("composer_info") view_box = self._builder.get_object("view") self._disc_listbox = DiscListBox() self._disc_listbox.set_selection_mode_allowed(True) # TODO: The top of the coverart is the same vertical # position as the top of the album songs, however # since we set a top margins for the discbox # subtract that margin here. A cleaner solution is # appreciated. self._disc_listbox.set_margin_top(64 - 16) self._disc_listbox.set_margin_bottom(64) self._disc_listbox.set_margin_end(32) self._disc_listbox.connect("selection-changed", self._on_selection_changed) view_box.add(self._disc_listbox) # FIXME: Assigned to appease searchview # get_selected_tracks self.view = self._disc_listbox self.add(self._builder.get_object("AlbumWidget")) self.get_style_context().add_class("view") self.get_style_context().add_class("content-view") self.show_all()
class AlbumWidget(Gtk.EventBox): """Album widget. The album widget consists of an image with the album art on the left and a list of songs on the right. """ _duration = 0 def __repr__(self): return '<AlbumWidget>' @log def __init__(self, player, parent_view): """Initialize the AlbumWidget. :param player: The player object :param parent_view: The view this widget is part of """ Gtk.EventBox.__init__(self) self._songs = [] scale = self.get_scale_factor() self._cache = AlbumArtCache(scale) self._loading_icon_surface = DefaultIcon(scale).get( DefaultIcon.Type.loading, ArtSize.large) self._player = player self._iter_to_clean = None self._selection_mode = False self._builder = Gtk.Builder() self._builder.add_from_resource('/org/gnome/Music/AlbumWidget.ui') self._create_model() self._album = None self._header_bar = None self._selection_mode_allowed = True self._composer_label = self._builder.get_object('composer_label') self._composer_info = self._builder.get_object('composer_info') view_box = self._builder.get_object('view') self._disc_listbox = DiscListBox() self._disc_listbox.set_selection_mode_allowed(True) # TODO: The top of the coverart is the same vertical # position as the top of the album songs, however # since we set a top margins for the discbox # subtract that margin here. A cleaner solution is # appreciated. self._disc_listbox.set_margin_top(64 - 16) self._disc_listbox.set_margin_bottom(64) self._disc_listbox.set_margin_end(32) self._disc_listbox.connect('selection-changed', self._on_selection_changed) view_box.add(self._disc_listbox) # FIXME: Assigned to appease searchview # _get_selected_songs self.view = self._disc_listbox self.add(self._builder.get_object('AlbumWidget')) self.get_style_context().add_class('view') self.get_style_context().add_class('content-view') self.show_all() @log def _on_selection_mode_request(self, *args): """Selection mode toggled.""" self._header_bar._select_button.clicked() @log def _create_model(self): """Create the ListStore model for this widget.""" self._model = Gtk.ListStore( GObject.TYPE_STRING, # title GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GdkPixbuf.Pixbuf, # icon GObject.TYPE_OBJECT, # song object GObject.TYPE_BOOLEAN, # item selected GObject.TYPE_STRING, GObject.TYPE_BOOLEAN, GObject.TYPE_INT, # icon shown GObject.TYPE_BOOLEAN, GObject.TYPE_INT) @log def update(self, artist, album, item, header_bar, selection_toolbar): """Update the album widget. :param str artist: The artist name :param str album: The album name :param item: The grilo media item :param header_bar: The header bar object :param selection_toolbar: The selection toolbar object """ # reset view self._songs = [] self._create_model() for widget in self._disc_listbox.get_children(): self._disc_listbox.remove(widget) self.selection_toolbar = selection_toolbar self._header_bar = header_bar self._album = album self._builder.get_object('cover').set_from_surface( self._loading_icon_surface) self._cache.lookup(item, ArtSize.large, self._on_lookup, None) self._duration = 0 GLib.idle_add(grilo.populate_album_songs, item, self.add_item) header_bar._select_button.connect( 'toggled', self._on_header_select_button_toggled) header_bar._cancel_button.connect( 'clicked', self._on_header_cancel_button_clicked) # FIXME: use utils escaped_artist = GLib.markup_escape_text(artist) escaped_album = GLib.markup_escape_text(album) self._builder.get_object('artist_label').set_markup(escaped_artist) self._builder.get_object('title_label').set_markup(escaped_album) if (item.get_creation_date()): self._builder.get_object('released_label_info').set_text( str(item.get_creation_date().get_year())) else: self._builder.get_object('released_label_info').set_text('----') self._set_composer_label(item) self._player.connect('playlist-item-changed', self._update_model) @log def _set_composer_label(self, item): composer = item.get_composer() show = False if composer: self._composer_info.set_text(composer) show = True self._composer_label.set_visible(show) self._composer_info.set_visible(show) @log def _on_selection_changed(self, widget): items = self._disc_listbox.get_selected_items() self.selection_toolbar._add_to_playlist_button.set_sensitive( len(items) > 0) if len(items) > 0: self._header_bar._selection_menu_label.set_text( ngettext("Selected %d item", "Selected %d items", len(items)) % len(items)) else: self._header_bar._selection_menu_label.set_text( _("Click on items to select them")) @log def _on_header_cancel_button_clicked(self, button): """Cancel selection mode callback.""" self._disc_listbox.set_selection_mode(False) self._header_bar.set_selection_mode(False) self._header_bar.header_bar.title = self._album @log def _on_header_select_button_toggled(self, button): """Selection mode button clicked callback.""" if button.get_active(): self._selection_mode = True self._disc_listbox.set_selection_mode(True) self._header_bar.set_selection_mode(True) self._player.actionbar.set_visible(False) self._header_bar.header_bar.set_custom_title( self._header_bar._selection_menu_button) else: self._selection_mode = False self._disc_listbox.set_selection_mode(False) self._header_bar.set_selection_mode(False) if (self._player.get_playback_status() != 2): self._player.actionbar.set_visible(True) @log def _create_disc_box(self, disc_nr, disc_songs): disc_box = DiscBox(self._model) disc_box.set_songs(disc_songs) disc_box.set_disc_number(disc_nr) disc_box.set_columns(1) disc_box.show_song_numbers(False) disc_box.connect('song-activated', self._song_activated) disc_box.connect('selection-toggle', self._selection_mode_toggled) return disc_box @log def _selection_mode_toggled(self, widget): if not self._selection_mode_allowed: return self._selection_mode = not self._selection_mode self._on_selection_mode_request() @log def _song_activated(self, widget, song_widget): if not song_widget.can_be_played: return if self._selection_mode: song_widget.check_button.toggled() return self._player.stop() self._player.set_playlist('Album', self._album, song_widget.model, song_widget.itr, 5, 11) self._player.set_playing(True) return True @log def add_item(self, source, prefs, song, remaining, data=None): """Add a song to the item to album list. :param source: The grilo source :param prefs: :param song: The grilo media object :param remaining: Remaining number of items to add :param data: User data """ if song: self._songs.append(song) self._duration = self._duration + song.get_duration() return discs = {} for song in self._songs: disc_nr = song.get_album_disc_number() if disc_nr not in discs.keys(): discs[disc_nr] = [song] else: discs[disc_nr].append(song) for disc_nr in discs: disc = self._create_disc_box(disc_nr, discs[disc_nr]) self._disc_listbox.add(disc) if len(discs) == 1: disc.show_disc_label(False) if remaining == 0: self._builder.get_object('running_length_label_info').set_text( _("%d min") % (int(self._duration / 60) + 1)) self.show_all() @log def _on_lookup(self, surface, data=None): """Albumart retrieved callback. :param surface: The Cairo surface retrieved :param path: The filesystem location the pixbuf :param data: User data """ self._builder.get_object('cover').set_from_surface(surface) @log def _update_model(self, player, playlist, current_iter): """Player changed callback. :param player: The player object :param playlist: The current playlist :param current_iter: The current iter of the playlist model """ if (playlist != self._model): return True current_song = playlist[current_iter][5] self._duration = 0 song_passed = False _iter = playlist.get_iter_first() while _iter: song = playlist[_iter][5] song_widget = song.song_widget self._duration += song.get_duration() escaped_title = GLib.markup_escape_text( utils.get_media_title(song)) if (song == current_song): song_widget.now_playing_sign.show() song_widget.title.set_markup("<b>{}</b>".format(escaped_title)) song_passed = True elif (song_passed): song_widget.now_playing_sign.hide() song_widget.title.set_markup( "<span>{}</span>".format(escaped_title)) else: song_widget.now_playing_sign.hide() song_widget.title.set_markup( "<span color=\'grey\'>{}</span>".format(escaped_title)) _iter = playlist.iter_next(_iter) self._builder.get_object('running_length_label_info').set_text( _("%d min") % (int(self._duration / 60) + 1)) return True @log def select_all(self): self._disc_listbox.select_all() @log def select_none(self): self._disc_listbox.select_none()
class AlbumWidget(Gtk.EventBox): """Album widget. The album widget consists of an image with the album art on the left and a list of songs on the right. """ _duration = 0 def __repr__(self): return "<AlbumWidget>" @log def __init__(self, player, parent_view): """Initialize the AlbumWidget. :param player: The player object :param parent_view: The view this widget is part of """ Gtk.EventBox.__init__(self) self._tracks = [] scale = self.get_scale_factor() self._cache = AlbumArtCache(scale) self._loading_icon_surface = DefaultIcon(scale).get(DefaultIcon.Type.loading, ArtSize.large) self._player = player self._iter_to_clean = None self._selection_mode = False self._builder = Gtk.Builder() self._builder.add_from_resource("/org/gnome/Music/AlbumWidget.ui") self._create_model() self._album = None self._header_bar = None self._selection_mode_allowed = True self._composer_label = self._builder.get_object("composer_label") self._composer_info = self._builder.get_object("composer_info") view_box = self._builder.get_object("view") self._disc_listbox = DiscListBox() self._disc_listbox.set_selection_mode_allowed(True) # TODO: The top of the coverart is the same vertical # position as the top of the album songs, however # since we set a top margins for the discbox # subtract that margin here. A cleaner solution is # appreciated. self._disc_listbox.set_margin_top(64 - 16) self._disc_listbox.set_margin_bottom(64) self._disc_listbox.set_margin_end(32) self._disc_listbox.connect("selection-changed", self._on_selection_changed) view_box.add(self._disc_listbox) # FIXME: Assigned to appease searchview # get_selected_tracks self.view = self._disc_listbox self.add(self._builder.get_object("AlbumWidget")) self.get_style_context().add_class("view") self.get_style_context().add_class("content-view") self.show_all() @log def _on_selection_mode_request(self, *args): """Selection mode toggled.""" self._header_bar._select_button.clicked() @log def _create_model(self): """Create the ListStore model for this widget.""" self._model = Gtk.ListStore( GObject.TYPE_STRING, # title GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GdkPixbuf.Pixbuf, # icon GObject.TYPE_OBJECT, # song object GObject.TYPE_BOOLEAN, # item selected GObject.TYPE_STRING, GObject.TYPE_BOOLEAN, GObject.TYPE_INT, # icon shown GObject.TYPE_BOOLEAN, GObject.TYPE_INT, ) @log def update(self, artist, album, item, header_bar, selection_toolbar): """Update the album widget. :param str artist: The artist name :param str album: The album name :param item: The grilo media item :param header_bar: The header bar object :param selection_toolbar: The selection toolbar object """ # reset view self._tracks = [] self._create_model() for widget in self._disc_listbox.get_children(): self._disc_listbox.remove(widget) self.selection_toolbar = selection_toolbar self._header_bar = header_bar self._album = album self._builder.get_object("cover").set_from_surface(self._loading_icon_surface) self._cache.lookup(item, ArtSize.large, self._on_lookup, None) self._duration = 0 GLib.idle_add(grilo.populate_album_songs, item, self.add_item) header_bar._select_button.connect("toggled", self._on_header_select_button_toggled) header_bar._cancel_button.connect("clicked", self._on_header_cancel_button_clicked) # FIXME: use utils escaped_artist = GLib.markup_escape_text(artist) escaped_album = GLib.markup_escape_text(album) self._builder.get_object("artist_label").set_markup(escaped_artist) self._builder.get_object("title_label").set_markup(escaped_album) if item.get_creation_date(): self._builder.get_object("released_label_info").set_text(str(item.get_creation_date().get_year())) else: self._builder.get_object("released_label_info").set_text("----") self._set_composer_label(item) self._player.connect("playlist-item-changed", self._update_model) @log def _set_composer_label(self, item): composer = item.get_composer() show = False if composer: self._composer_info.set_text(composer) show = True self._composer_label.set_visible(show) self._composer_info.set_visible(show) @log def _on_selection_changed(self, widget): items = self._disc_listbox.get_selected_items() self.selection_toolbar._add_to_playlist_button.set_sensitive(len(items) > 0) if len(items) > 0: self._header_bar._selection_menu_label.set_text( ngettext("Selected %d item", "Selected %d items", len(items)) % len(items) ) else: self._header_bar._selection_menu_label.set_text(_("Click on items to select them")) @log def _on_header_cancel_button_clicked(self, button): """Cancel selection mode callback.""" self._disc_listbox.set_selection_mode(False) self._header_bar.set_selection_mode(False) self._header_bar.header_bar.title = self._album @log def _on_header_select_button_toggled(self, button): """Selection mode button clicked callback.""" if button.get_active(): self._selection_mode = True self._disc_listbox.set_selection_mode(True) self._header_bar.set_selection_mode(True) self._player.actionbar.set_visible(False) self._header_bar.header_bar.set_custom_title(self._header_bar._selection_menu_button) else: self._selection_mode = False self._disc_listbox.set_selection_mode(False) self._header_bar.set_selection_mode(False) if self._player.get_playback_status() != 2: self._player.actionbar.set_visible(True) @log def _create_disc_box(self, disc_nr, disc_tracks): disc_box = DiscBox(self._model) disc_box.set_tracks(disc_tracks) disc_box.set_disc_number(disc_nr) disc_box.set_columns(1) disc_box.show_song_numbers(False) disc_box.connect("track-activated", self._track_activated) disc_box.connect("selection-toggle", self._selection_mode_toggled) return disc_box @log def _selection_mode_toggled(self, widget): if not self._selection_mode_allowed: return self._selection_mode = not self._selection_mode self._on_selection_mode_request() @log def _track_activated(self, widget, song_widget): if not song_widget.can_be_played: return if self._selection_mode: song_widget.check_button.toggled() return self._player.stop() self._player.set_playlist("Artist", "test", song_widget.model, song_widget.itr, 5, 11) self._player.set_playing(True) return True @log def add_item(self, source, prefs, track, remaining, data=None): """Add a song to the item to album list. :param source: The grilo source :param prefs: :param track: The grilo media object :param remaining: Remaining number of items to add :param data: User data """ if track: self._tracks.append(track) self._duration = self._duration + track.get_duration() return discs = {} for track in self._tracks: disc_nr = track.get_album_disc_number() if disc_nr not in discs.keys(): discs[disc_nr] = [track] else: discs[disc_nr].append(track) for disc_nr in discs: disc = self._create_disc_box(disc_nr, discs[disc_nr]) self._disc_listbox.add(disc) if len(discs) == 1: disc.show_disc_label(False) if remaining == 0: self._builder.get_object("running_length_label_info").set_text(_("%d min") % (int(self._duration / 60) + 1)) self.show_all() @log def _on_lookup(self, surface, data=None): """Albumart retrieved callback. :param surface: The Cairo surface retrieved :param path: The filesystem location the pixbuf :param data: User data """ self._builder.get_object("cover").set_from_surface(surface) @log def _update_model(self, player, playlist, current_iter): """Player changed callback. :param player: The player object :param playlist: The current playlist :param current_iter: The current iter of the playlist model """ if playlist != self._model: return True current_song = playlist[current_iter][5] self._duration = 0 song_passed = False _iter = playlist.get_iter_first() while _iter: song = playlist[_iter][5] song_widget = song.song_widget self._duration += song.get_duration() escaped_title = GLib.markup_escape_text(utils.get_media_title(song)) if song == current_song: song_widget.now_playing_sign.show() song_widget.title.set_markup("<b>{}</b>".format(escaped_title)) song_passed = True elif song_passed: song_widget.now_playing_sign.hide() song_widget.title.set_markup("<span>{}</span>".format(escaped_title)) else: song_widget.now_playing_sign.hide() song_widget.title.set_markup("<span color='grey'>{}</span>".format(escaped_title)) _iter = playlist.iter_next(_iter) self._builder.get_object("running_length_label_info").set_text(_("%d min") % (int(self._duration / 60) + 1)) return True @log def select_all(self): self._disc_listbox.select_all() @log def select_none(self): self._disc_listbox.select_none()