def __init__(self, playlist_name): Gtk.Bin.__init__(self) self._playlist_name = playlist_name self._tracks = [] self._main_widget = Gtk.Grid() self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self.add(self._main_widget)
def __init__(self, playlist_id): """ Init playlist Widget @param playlist id as int @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_id = playlist_id self._tracks1 = [] self._tracks2 = [] self._stop = False main_widget = Gtk.Grid() main_widget.set_property('margin', 10) main_widget.set_property('column-spacing', 10) main_widget.show() loved = playlist_id != Type.LOVED self._tracks_widget1 = TracksWidget(False, loved) self._tracks_widget2 = TracksWidget(False, loved) self._tracks_widget1.connect('activated', self._on_activated) self._tracks_widget2.connect('activated', self._on_activated) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) main_widget.add(self._tracks_widget1) main_widget.add(self._tracks_widget2) self.add(main_widget)
def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Bin.__init__(self) self._playlist_ids = playlist_ids self._tracks1 = [] self._tracks2 = [] self._width = None self._orientation = None self._stop = False # Used to block widget2 populate while showing one column self._locked_widget2 = True self._box = Gtk.Grid() self._box.set_column_homogeneous(True) self._box.set_property('valign', Gtk.Align.START) self._box.show() self.connect('size-allocate', self._on_size_allocate) self._tracks_widget_left = TracksWidget() self._tracks_widget_right = TracksWidget() self._tracks_widget_left.connect('activated', self._on_activated) self._tracks_widget_right.connect('activated', self._on_activated) self._tracks_widget_left.show() self._tracks_widget_right.show() self.add(self._box)
def __init__(self, playlist_name): Gtk.Bin.__init__(self) self._playlist_name = playlist_name self._tracks = [] self._stop = False self._main_widget = Gtk.Grid() self._main_widget.set_property('margin', 10) self._main_widget.set_property('column-spacing', 10) self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self.add(self._main_widget)
def __add_disc_container(self, disc_number): """ Add disc container to box @param disc_number as int """ self._tracks_left[disc_number] = TracksWidget() self._tracks_right[disc_number] = TracksWidget() self._tracks_left[disc_number].connect("activated", self.__on_activated) self._tracks_right[disc_number].connect("activated", self.__on_activated) self._tracks_left[disc_number].show() self._tracks_right[disc_number].show()
def __init__(self, playlist_id, playlist_name): """ Init playlist Widget @param playlist id as int @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_id = playlist_id self._playlist_name = playlist_name self._tracks1 = [] self._tracks2 = [] self._stop = False self._main_widget = Gtk.Grid() self._main_widget.set_property('margin', 10) self._main_widget.set_property('column-spacing', 10) self._main_widget.show() loved = playlist_name != Lp.playlists._LOVED self._tracks_widget1 = TracksWidget(False, loved) self._tracks_widget2 = TracksWidget(False, loved) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self._stack = Gtk.Stack() self._stack.set_transition_duration(250) self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self._stack.show() spinner = Gtk.Spinner() spinner.start() spinner.show() self._stack.add(spinner) self._stack.add(self._main_widget) self._stack.set_visible_child(spinner) self.add(self._stack)
def _add_disc_container(self, disc_number): """ Add disc container to box @param disc_number as int """ self._tracks_left[disc_number] = TracksWidget() self._tracks_right[disc_number] = TracksWidget() self._tracks_left[disc_number].connect('activated', self._on_activated) self._tracks_left[disc_number].connect('button-press-event', self._on_button_press_event) self._tracks_right[disc_number].connect('activated', self._on_activated) self._tracks_right[disc_number].connect('button-press-event', self._on_button_press_event) self._tracks_left[disc_number].show() self._tracks_right[disc_number].show()
def __init__(self, playlist_id, playlist_name): """ Init playlist Widget @param playlist id as int @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_id = playlist_id self._playlist_name = playlist_name self._tracks1 = [] self._tracks2 = [] self._stop = False self._main_widget = Gtk.Grid() self._main_widget.set_property('margin', 10) self._main_widget.set_property('column-spacing', 10) self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self._stack = Gtk.Stack() self._stack.set_transition_duration(250) self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self._stack.show() spinner = Gtk.Spinner() spinner.start() spinner.show() self._stack.add(spinner) self._stack.add(self._main_widget) self._stack.set_visible_child(spinner) self.add(self._stack)
def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_ids = playlist_ids self._tracks1 = [] self._tracks2 = [] self._width = None self._stop = False # Used to block widget2 populate while showing one column self._locked_widget2 = True self._box = FlowBox() self._box.set_selection_mode(Gtk.SelectionMode.NONE) self._box.set_hexpand(True) self._box.set_property('valign', Gtk.Align.START) self._box.show() self.connect('size-allocate', self._on_size_allocate) loved = playlist_ids and playlist_ids[0] != Type.LOVED self._tracks_widget_left = TracksWidget(loved) self._tracks_widget_right = TracksWidget(loved) self._tracks_widget_left.connect('track-moved', self._on_track_moved) self._tracks_widget_right.connect('track-moved', self._on_track_moved) self._tracks_widget_left.connect('activated', self._on_activated) self._tracks_widget_right.connect('activated', self._on_activated) self._tracks_widget_left.show() self._tracks_widget_right.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget_left) size_group.add_widget(self._tracks_widget_right) self._box.add(self._tracks_widget_left) self._box.add(self._tracks_widget_right) self.add(self._box)
def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Grid.__init__(self) self.set_row_spacing(5) self.set_orientation(Gtk.Orientation.VERTICAL) self.__playlist_ids = playlist_ids self.__tracks_left = [] self.__tracks_right = [] self.__width = None self.__orientation = None self.__loading = Loading.NONE # Used to block widget2 populate while showing one column self.__locked_widget_right = True self.__grid = Gtk.Grid() self.__grid.set_vexpand(True) self.__grid.set_column_homogeneous(True) self.__grid.show() self.connect("size-allocate", self.__on_size_allocate) self.__tracks_widget_left = TracksWidget(True) self.__tracks_widget_left.set_vexpand(True) self.__tracks_widget_right = TracksWidget(True) self.__tracks_widget_right.set_vexpand(True) self.__tracks_widget_left.connect("activated", self.__on_activated) self.__tracks_widget_right.connect("activated", self.__on_activated) self.__tracks_widget_left.show() self.__tracks_widget_right.show() self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, [], Gdk.DragAction.MOVE) self.drag_dest_add_text_targets() self.connect("drag-data-received", self.__on_drag_data_received) self.add(self.__grid)
def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Grid.__init__(self) self.set_row_spacing(5) self.set_orientation(Gtk.Orientation.VERTICAL) self._playlist_ids = playlist_ids self._tracks_left = [] self._tracks_right = [] self._width = None self._orientation = None self._loading = Loading.NONE # Used to block widget2 populate while showing one column self._locked_widget_right = True self._box = Gtk.Grid() self._box.set_vexpand(True) self._box.set_column_homogeneous(True) self._box.show() self.connect('size-allocate', self._on_size_allocate) self._tracks_widget_left = TracksWidget(True) self._tracks_widget_left.set_vexpand(True) self._tracks_widget_right = TracksWidget(True) self._tracks_widget_right.set_vexpand(True) self._tracks_widget_left.connect('activated', self._on_activated) self._tracks_widget_right.connect('activated', self._on_activated) self._tracks_widget_left.show() self._tracks_widget_right.show() self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, [], Gdk.DragAction.MOVE) self.drag_dest_add_text_targets() self.connect('drag-data-received', self._on_drag_data_received) self.add(self._box)
def __init__(self, album_id, genre_id, pop_allowed, scrolled, size_group): """ Init detailed album widget @param album id as int @param genre id as int @param parent width as int @param pop_allowed as bool if widget can show popovers @param scrolled as bool @param size group as Gtk.SizeGroup """ AlbumWidget.__init__(self, album_id, genre_id=genre_id) builder = Gtk.Builder() if scrolled: builder.add_from_resource( '/org/gnome/Lollypop/AlbumContextWidget.ui') else: builder.add_from_resource( '/org/gnome/Lollypop/AlbumDetailedWidget.ui') rating = RatingWidget(self._album) rating.show() builder.get_object('coverbox').add(rating) builder.connect_signals(self) if scrolled: builder.get_object('artist').set_text(self._album.artist_name) builder.get_object('artist').show() grid = builder.get_object('tracks') self._discs = self._album.discs self._tracks_left = {} self._tracks_right = {} show_label = len(self._discs) > 1 i = 0 for disc in self._discs: index = disc.number if show_label: label = Gtk.Label() label.set_text(_("Disc %s") % index) label.set_property('halign', Gtk.Align.START) label.get_style_context().add_class('dim-label') if i: label.set_property('margin-top', 30) label.show() grid.attach(label, 0, i, 2, 1) i += 1 sep = Gtk.Separator() sep.set_property('margin-bottom', 2) sep.show() grid.attach(sep, 0, i, 2, 1) i += 1 self._tracks_left[index] = TracksWidget(pop_allowed) self._tracks_right[index] = TracksWidget(pop_allowed) grid.attach(self._tracks_left[index], 0, i, 1, 1) grid.attach(self._tracks_right[index], 1, i, 1, 1) size_group.add_widget(self._tracks_left[index]) size_group.add_widget(self._tracks_right[index]) self._tracks_left[index].connect('activated', self._on_activated) self._tracks_left[index].connect('button-press-event', self._on_button_press_event) self._tracks_right[index].connect('activated', self._on_activated) self._tracks_right[index].connect('button-press-event', self._on_button_press_event) self._tracks_left[index].show() self._tracks_right[index].show() i += 1 self._cover = builder.get_object('cover') self.set_cover() builder.get_object('title').set_label(self._album.name) builder.get_object('year').set_label(self._album.year) self.add(builder.get_object('AlbumDetailedWidget')) if pop_allowed: self._menu = builder.get_object('menu') self._eventbox = builder.get_object('eventbox') self._eventbox.connect('realize', self._on_eventbox_realize) self._eventbox.connect("button-press-event", self._on_cover_press_event) self._menu.connect('clicked', self._pop_menu) self._menu.show() else: self._eventbox = None
def __init__(self, album_id, genre_id, show_menu, scrolled, size_group): AlbumWidget.__init__(self, album_id) self._artist_id = Objects.albums.get_artist_id(album_id) self._album_id = album_id self._genre_id = genre_id builder = Gtk.Builder() if scrolled: builder.add_from_resource( '/org/gnome/Lollypop/AlbumContextWidget.ui') else: builder.add_from_resource( '/org/gnome/Lollypop/AlbumDetailedWidget.ui') builder.connect_signals(self) self._stars = [] self._stars.append(builder.get_object('star0')) self._stars.append(builder.get_object('star1')) self._stars.append(builder.get_object('star2')) self._stars.append(builder.get_object('star3')) self._stars.append(builder.get_object('star4')) self._on_leave_notify(None, None) grid = builder.get_object('tracks') self._discs = Objects.albums.get_discs(album_id, genre_id) self._tracks_left = {} self._tracks_right = {} show_label = len(self._discs) > 1 i = 0 for disc in self._discs: if show_label: label = Gtk.Label() label.set_text(_("Disc %s") % disc) label.set_property('halign', Gtk.Align.START) label.get_style_context().add_class('dim-label') if i: label.set_property('margin-top', 30) label.show() grid.attach(label, 0, i, 2, 1) i += 1 sep = Gtk.Separator() sep.show() grid.attach(sep, 0, i ,2 ,1) i += 1 self._tracks_left[disc] = TracksWidget(show_menu) self._tracks_right[disc] = TracksWidget(show_menu) grid.attach(self._tracks_left[disc], 0, i, 1, 1) grid.attach(self._tracks_right[disc], 1, i, 1, 1) size_group.add_widget(self._tracks_left[disc]) size_group.add_widget(self._tracks_right[disc]) self._tracks_left[disc].connect('activated', self._on_activated) self._tracks_left[disc].connect('button-press-event', self._on_button_press_event) self._tracks_right[disc].connect('activated', self._on_activated) self._tracks_right[disc].connect('button-press-event', self._on_button_press_event) self._tracks_left[disc].show() self._tracks_right[disc].show() i += 1 self._cover = builder.get_object('cover') self.set_cover() builder.get_object('title').set_label( Objects.albums.get_name(album_id)) builder.get_object('year').set_label( Objects.albums.get_year(album_id)) self.add(builder.get_object('AlbumDetailedWidget')) if show_menu: self._menu = builder.get_object('menu') self._eventbox = builder.get_object('eventbox') self._eventbox.connect('realize', self._on_eventbox_realize) self._eventbox.connect("button-press-event", self._show_web_art) self._menu.connect('clicked', self._pop_menu) self._menu.show() else: self._eventbox = None
class PlaylistWidget(Gtk.Bin): """ Init playlist Widget @param playlist name as str """ def __init__(self, playlist_name): Gtk.Bin.__init__(self) self._playlist_name = playlist_name self._tracks = [] self._stop = False self._main_widget = Gtk.Grid() self._main_widget.set_property('margin', 10) self._main_widget.set_property('column-spacing', 10) self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self.add(self._main_widget) """ Populate list one, thread safe @param track's ids as array of int @param track position as int """ def populate_list_one(self, tracks, pos): self._stop = False self._tracks = list(tracks) GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos) """ Populate list two, thread safe @param track's ids as array of int @param track position as int """ def populate_list_two(self, tracks, pos): self._stop = False self._tracks += list(tracks) GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos) """ Update playing indicator """ def update_playing_indicator(self): self._tracks_widget1.update_playing(Lp.player.current_track.id) self._tracks_widget2.update_playing(Lp.player.current_track.id) """ Stop loading """ def stop(self): self._stop = True """ Clear tracks """ def clear(self): self._tracks = [] for child in self._tracks_widget1.get_children(): child.destroy() for child in self._tracks_widget2.get_children(): child.destroy() ####################### # PRIVATE # ####################### """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param previous album id as int """ def _add_tracks(self, tracks, widget, pos, previous_album_id=None): if not tracks or self._stop: return track_id = tracks.pop(0) if track_id == -1: return (title, filepath, length, album_id) =\ Lp.tracks.get_infos(track_id) if title is None: return else: title = escape(title) artist_id = Lp.albums.get_artist_id(album_id) artist_ids = Lp.tracks.get_artist_ids(track_id) # If we are listening to a compilation, prepend artist name if artist_id == Type.COMPILATIONS or\ len(artist_ids) > 1 or\ artist_id not in artist_ids: artist_name = "" for artist_id in artist_ids: artist_name += translate_artist_name( Lp.artists.get_name(artist_id)) + ", " title = "<b>%s</b>\n%s" % (escape(artist_name[:-2]), title) if album_id != previous_album_id: widget.add_album(track_id, album_id, pos, title, length, None) else: widget.add_track(track_id, pos, title, length, None) GLib.idle_add(self._add_tracks, tracks, widget, pos+1, album_id) """ On track activation, play track @param widget as TracksWidget @param track id as int @param playlist name as str """ def _on_activated(self, widget, track_id, playlist_name): if not Lp.player.is_party(): track = Lp.player.set_user_playlist(self._tracks, track_id) if track is not None: Lp.player.load(track) else: Lp.player.load(Track(track_id))
class PlaylistWidget(Gtk.Bin): """ Init playlist Widget @param playlist name as str """ def __init__(self, playlist_name): Gtk.Bin.__init__(self) self._playlist_name = playlist_name self._tracks = [] self._main_widget = Gtk.Grid() self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self.add(self._main_widget) """ Populate list one, thread safe @param track's ids as array of int @param track position as int """ def populate_list_one(self, tracks, pos): GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos) """ Populate list two, thread safe @param track's ids as array of int @param track position as int """ def populate_list_two(self, tracks, pos): GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos) """ Update playing indicator """ def update_playing_indicator(self): self._tracks_widget1.update_playing(Objects.player.current.id) self._tracks_widget2.update_playing(Objects.player.current.id) """ Clear tracks """ def clear(self): self._tracks = [] for child in self._tracks_widget1.get_children(): child.destroy() for child in self._tracks_widget2.get_children(): child.destroy() ####################### # PRIVATE # ####################### """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int """ def _add_tracks(self, tracks, widget, pos): if not tracks: return track_id = tracks.pop(0) if track_id == -1: return (title, filepath, length, album_id) =\ Objects.tracks.get_infos(track_id) artist_name = "" for artist_id in Objects.tracks.get_artist_ids(track_id): artist_name += translate_artist_name( Objects.artists.get_name(artist_id)) + ", " title = "<b>%s</b>\n%s" % (escape(artist_name[:-2]), escape(title)) widget.add_track(track_id, pos, title, length, None, True) GLib.idle_add(self._add_tracks, tracks, widget, pos + 1) """ On track activation, play track @param widget as TracksWidget @param track id as int @param playlist name as str """ def _on_activated(self, widget, track_id, playlist_name): if not Objects.player.is_party(): if not self._tracks: self._tracks = Objects.playlists.get_tracks_id(playlist_name) Objects.player.set_user_playlist(self._tracks, track_id) Objects.player.load(track_id)
class PlaylistsWidget(Gtk.Bin): """ Show playlist tracks/albums """ def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Bin.__init__(self) self._playlist_ids = playlist_ids self._tracks1 = [] self._tracks2 = [] self._width = None self._orientation = None self._stop = False # Used to block widget2 populate while showing one column self._locked_widget2 = True self._box = Gtk.Grid() self._box.set_column_homogeneous(True) self._box.set_property('valign', Gtk.Align.START) self._box.show() self.connect('size-allocate', self._on_size_allocate) self._tracks_widget_left = TracksWidget() self._tracks_widget_right = TracksWidget() self._tracks_widget_left.connect('activated', self._on_activated) self._tracks_widget_right.connect('activated', self._on_activated) self._tracks_widget_left.show() self._tracks_widget_right.show() self.add(self._box) def get_id(self): """ Return playlist widget id @return int """ return Type.PLAYLISTS def update_overlay(self): """ No overlay here now """ pass def update_state(self): """ No state to update """ pass def update_cover(self): """ No update cover for now """ pass def get_current_ordinate(self): """ If current track in widget, return it ordinate, @return y as int """ ordinate = None for child in self._tracks_widget_left.get_children() + \ self._tracks_widget_right.get_children(): if child.get_id() == Lp().player.current_track.id: ordinate = child.translate_coordinates(self._box, 0, 0)[1] return ordinate def populate_list_left(self, tracks, pos): """ Populate left list @param track's ids as array of int (not null) @param track position as int @thread safe """ # We reset width here to allow size allocation code to run self._width = None self._tracks1 = list(tracks) GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_left, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track's ids as array of int (not null) @param track position as int @thread safe """ self._tracks2 = list(tracks) # If we are showing only one column, wait for widget1 if self._orientation == Gtk.Orientation.VERTICAL and\ self._locked_widget2: GLib.timeout_add(100, self.populate_list_right, tracks, pos) else: # We reset width here to allow size allocation code to run self._width = None GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_right, pos) def update_playing_indicator(self): """ Update playing indicator """ self._tracks_widget_left.update_playing(Lp().player.current_track.id) self._tracks_widget_right.update_playing(Lp().player.current_track.id) def stop(self): """ Stop loading """ self._stop = True def append(self, track_id): """ Add track to widget @param track id as int """ self._add_tracks([track_id], self._tracks_widget_right, -1) self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks1) + 1) def remove(self, track_id): """ Del track from widget @param track id as int """ children = self._tracks_widget_left.get_children() + \ self._tracks_widget_right.get_children() # Clear the widget if track_id is None: for child in children: child.destroy() self._update_tracks() else: for child in children: if child.get_id() == track_id: child.destroy() break self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks1) + 1) ####################### # PRIVATE # ####################### def _add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param pos as int @param previous album id as int """ if not tracks or self._stop: if widget == self._tracks_widget_right: self._stop = False else: self._locked_widget2 = False return track = Track(tracks.pop(0)) row = PlaylistRow(track.id, pos, track.album.id != previous_album_id) row.connect('track-moved', self._on_track_moved) row.show() widget.insert(row, pos) GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, track.album.id) def _update_tracks(self): """ Update tracks based on current widget """ # Recalculate tracks self._tracks1 = [] self._tracks2 = [] for child in self._tracks_widget_left.get_children(): self._tracks1.append(child.get_id()) for child in self._tracks_widget_right.get_children(): self._tracks2.append(child.get_id()) def _update_position(self): """ Update widget position """ len_tracks1 = len(self._tracks1) len_tracks2 = len(self._tracks2) # Take first track from tracks2 and put it at the end of tracks1 if len_tracks2 > len_tracks1: src = self._tracks2[0] if self._tracks1: dst = self._tracks1[-1] else: dst = -1 self._move_track(dst, src, False) # Take last track of tracks1 and put it at the bottom of tracks2 elif len_tracks1 - 1 > len_tracks2: src = self._tracks1[-1] if self._tracks2: dst = self._tracks2[0] else: dst = -1 self._move_track(dst, src, True) self._update_tracks() def _update_headers(self): """ Update headers for all tracks """ self._tracks_widget_left.update_headers() prev_album_id = None if self._orientation == Gtk.Orientation.VERTICAL: if self._tracks1: prev_album_id = Track(self._tracks1[-1]).album.id self._tracks_widget_right.update_headers(prev_album_id) def _move_track(self, dst, src, up): """ Move track from src to row @param dst as int @param src as int @param up as bool @return (dst_widget as TracksWidget, src index as int, dst index as int) """ tracks1_len = len(self._tracks1) tracks2_len = len(self._tracks2) if src in self._tracks1: src_widget = self._tracks_widget_left src_index = self._tracks1.index(src) - 1 else: src_widget = self._tracks_widget_right src_index = self._tracks2.index(src) - 1 if tracks1_len == 0 or dst in self._tracks1: dst_widget = self._tracks_widget_left dst_tracks = self._tracks1 elif tracks2_len == 0 or dst in self._tracks2: dst_widget = self._tracks_widget_right dst_tracks = self._tracks2 else: return # Remove src from src_widget for child in src_widget.get_children(): if child.get_id() == src: child.destroy() break src_track = Track(src) prev_track = Track() name = escape(src_track.name) index = 0 # Get previous track if dst != -1: for child in dst_widget.get_children(): if child.get_id() == dst: break index += 1 if not up: index += 1 # Get previous track (in dst context) prev_index = dst_tracks.index(dst) if up: prev_index -= 1 prev_track = Track(dst_tracks[prev_index]) # If we are listening to a compilation, prepend artist name if (src_track.album.artist_id == Type.COMPILATIONS or len(src_track.artist_ids) > 1 or src_track.album.artist_id not in src_track.artist_ids): name = "<b>%s</b>\n%s" % (escape(", ".join( src_track.artists)), name) self._tracks1.insert(index, src_track.id) row = PlaylistRow( src_track.id, index, index == 0 or src_track.album.id != prev_track.album.id) row.connect('track-moved', self._on_track_moved) row.show() dst_widget.insert(row, index) return (src_widget, dst_widget, src_index, index) def _on_track_moved(self, widget, dst, src, up): """ Move track from src to row Recalculate track position @param widget as TracksWidget @param dst as int @param src as int @param up as bool """ (src_widget, dst_widget, src_index, dst_index) = \ self._move_track(dst, src, up) self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks1) + 1) # Save playlist in db only if one playlist visible if len(self._playlist_ids) == 1 and self._playlist_ids[0] >= 0: Lp().playlists.clear(self._playlist_ids[0], False) tracks = [] for track_id in self._tracks1 + self._tracks2: tracks.append(Track(track_id)) Lp().playlists.add_tracks(self._playlist_ids[0], tracks, False) if Lp().player.get_user_playlist_ids() == self._playlist_ids: Lp().player.populate_user_playlist_by_tracks( self._tracks1 + self._tracks2, self._playlist_ids) def _on_size_allocate(self, widget, allocation): """ Change box max/min children @param widget as Gtk.Widget @param allocation as Gtk.Allocation """ if self._width == allocation.width: return self._width = allocation.width redraw = False if allocation.width < WindowSize.MONSTER: orientation = Gtk.Orientation.VERTICAL else: orientation = Gtk.Orientation.HORIZONTAL if orientation != self._orientation: self._orientation = orientation redraw = True self._box.set_orientation(orientation) if redraw: for child in self._box.get_children(): self._box.remove(child) GLib.idle_add(self._box.add, self._tracks_widget_left) GLib.idle_add(self._box.add, self._tracks_widget_right) self._update_headers() def _on_activated(self, widget, track_id): """ On track activation, play track @param widget as TracksWidget @param track as Track """ Lp().player.load(Track(track_id)) if not Lp().player.is_party(): Lp().player.populate_user_playlist_by_tracks( self._tracks1 + self._tracks2, self._playlist_ids)
def __init__(self, album_id, genre_ids, artist_ids, popover, size_group): """ Init detailed album widget @param album id as int @param genre ids as [int] @param artist ids as [int] @param popover as bool @param size group as Gtk.SizeGroup """ Gtk.Bin.__init__(self) AlbumWidget.__init__(self, album_id, genre_ids) self._artist_ids = artist_ids self._pop_allowed = not popover or Gtk.get_minor_version() > 16 builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/%s.ui' % type(self).__name__) self._color = builder.get_object('color') rating = RatingWidget(self._album) rating.show() builder.get_object('coverbox').add(rating) builder.connect_signals(self) self._artist_label = builder.get_object('artist') if len(artist_ids) > 1: self._artist_label.set_text(self._album.artist_name) self._artist_label.show() label = builder.get_object('duration') duration = Lp().albums.get_duration(album_id, genre_ids) hours = int(duration / 3600) mins = int(duration / 60) if hours > 0: mins -= hours * 60 if mins > 0: label.set_text(_("%s h %s m") % (hours, mins)) else: label.set_text(_("%s h") % hours) else: label.set_text(_("%s m") % mins) grid = builder.get_object('tracks') self._discs = self._album.discs self._tracks_left = {} self._tracks_right = {} show_label = len(self._discs) > 1 i = 0 for disc in self._discs: index = disc.number if show_label: label = Gtk.Label() label.set_text(_("Disc %s") % index) label.set_property('halign', Gtk.Align.START) label.get_style_context().add_class('dim-label') if i: label.set_property('margin-top', 30) label.show() grid.attach(label, 0, i, 2, 1) i += 1 self._tracks_left[index] = TracksWidget(self._pop_allowed, True) self._tracks_right[index] = TracksWidget(self._pop_allowed, True) grid.attach(self._tracks_left[index], 0, i, 1, 1) grid.attach(self._tracks_right[index], 1, i, 1, 1) size_group.add_widget(self._tracks_left[index]) size_group.add_widget(self._tracks_right[index]) self._tracks_left[index].connect('activated', self._on_activated) self._tracks_left[index].connect('button-press-event', self._on_button_press_event) self._tracks_right[index].connect('activated', self._on_activated) self._tracks_right[index].connect('button-press-event', self._on_button_press_event) self._tracks_left[index].show() self._tracks_right[index].show() i += 1 self._cover = builder.get_object('cover') self.set_cover() self.update_state() builder.get_object('title').set_label(self._album.name) if self._album.year: year = builder.get_object('year') year.set_label(self._album.year) year.show() self.add(builder.get_object('widget')) # TODO: Remove this test later if self._pop_allowed: self._menu = builder.get_object('menu') self._menu.connect('clicked', self._pop_menu) self._menu.show()
class PlaylistWidget(Gtk.Bin): """ Show playlist tracks/albums """ def __init__(self, playlist_id, playlist_name): """ Init playlist Widget @param playlist id as int @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_id = playlist_id self._playlist_name = playlist_name self._tracks1 = [] self._tracks2 = [] self._stop = False self._main_widget = Gtk.Grid() self._main_widget.set_property('margin', 10) self._main_widget.set_property('column-spacing', 10) self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self._stack = Gtk.Stack() self._stack.set_transition_duration(250) self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self._stack.show() spinner = Gtk.Spinner() spinner.start() spinner.show() self._stack.add(spinner) self._stack.add(self._main_widget) self._stack.set_visible_child(spinner) self.add(self._stack) def populate_list_left(self, tracks, pos): """ Populate left list @param track's ids as array of int @param track position as int @thread safe """ GLib.idle_add(self._stack.set_visible_child, self._main_widget) self._stop = False GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track's ids as array of int @param track position as int @thread safe """ self._stop = False GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos) def update_playing_indicator(self): """ Update playing indicator """ self._tracks_widget1.update_playing(Lp.player.current_track.id) self._tracks_widget2.update_playing(Lp.player.current_track.id) def stop(self): """ Stop loading """ self._stop = True def clear(self): """ Clear tracks """ self._tracks = [] for child in self._tracks_widget1.get_children(): child.destroy() for child in self._tracks_widget2.get_children(): child.destroy() ####################### # PRIVATE # ####################### def _add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param previous album id as int """ if not tracks or self._stop: return track_id = tracks.pop(0) if track_id == -1: return (title, filepath, length, album_id) =\ Lp.tracks.get_infos(track_id) if title is None: return else: title = escape(title) artist_id = Lp.albums.get_artist_id(album_id) artist_ids = Lp.tracks.get_artist_ids(track_id) # If we are listening to a compilation, prepend artist name if artist_id == Type.COMPILATIONS or\ len(artist_ids) > 1 or\ artist_id not in artist_ids: artist_name = "" for artist_id in artist_ids: if artist_name != "": artist_name += ", " artist_name += Lp.artists.get_name(artist_id) title = "<b>%s</b>\n%s" % (escape(artist_name), title) if widget == self._tracks_widget1: self._tracks1.append(Track(track_id)) else: self._tracks2.append(Track(track_id)) if album_id != previous_album_id: widget.add_album(track_id, album_id, pos, title, length, None) else: widget.add_album(track_id, None, pos, title, length, None) GLib.idle_add(self._add_tracks, tracks, widget, pos+1, album_id) def _on_activated(self, widget, track_id, playlist_name): """ On track activation, play track @param widget as TracksWidget @param track as Track @param playlist name as str """ if Lp.player.is_party(): Lp.player.load(Track(track_id)) else: track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2, track_id) Lp.player.set_user_playlist_id(self._playlist_id) if track is not None: Lp.player.load(track)
class PlaylistWidget(Gtk.Bin): """ Show playlist tracks/albums """ def __init__(self, playlist_id): """ Init playlist Widget @param playlist id as int @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_id = playlist_id self._tracks1 = [] self._tracks2 = [] self._stop = False main_widget = Gtk.Grid() main_widget.set_property('margin', 10) main_widget.set_property('column-spacing', 10) main_widget.show() loved = playlist_id != Type.LOVED self._tracks_widget1 = TracksWidget(False, loved) self._tracks_widget2 = TracksWidget(False, loved) self._tracks_widget1.connect('activated', self._on_activated) self._tracks_widget2.connect('activated', self._on_activated) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) main_widget.add(self._tracks_widget1) main_widget.add(self._tracks_widget2) self.add(main_widget) def populate_list_left(self, tracks, pos): """ Populate left list @param track's ids as array of int @param track position as int @thread safe """ self._stop = False GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track's ids as array of int @param track position as int @thread safe """ self._stop = False GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos) def update_playing_indicator(self): """ Update playing indicator """ self._tracks_widget1.update_playing(Lp.player.current_track.id) self._tracks_widget2.update_playing(Lp.player.current_track.id) def stop(self): """ Stop loading """ self._stop = True def clear(self): """ Clear tracks """ self._tracks = [] for child in self._tracks_widget1.get_children(): child.destroy() for child in self._tracks_widget2.get_children(): child.destroy() ####################### # PRIVATE # ####################### def _add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param previous album id as int """ if not tracks or self._stop: return track = Track(tracks.pop(0)) name = escape(track.name) album = track.album if track.id is None: GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, previous_album_id) return # If we are listening to a compilation, prepend artist name if (album.artist_id == Type.COMPILATIONS or len(track.artist_ids) > 1 or album.artist_id not in track.artist_ids): name = "<b>%s</b>\n%s" % (escape(track.artist_names), name) if widget == self._tracks_widget1: self._tracks1.append(track) else: self._tracks2.append(track) if album.id != previous_album_id: widget.add_album(track.id, album, pos, name, track.duration, None) else: widget.add_album(track.id, None, pos, name, track.duration, None) GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, album.id) def _on_activated(self, widget, track_id): """ On track activation, play track @param widget as TracksWidget @param track as Track """ if Lp.player.is_party(): Lp.player.load(Track(track_id)) else: track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2, track_id) Lp.player.set_user_playlist_id(self._playlist_id) if track is not None: Lp.player.load(track)
class PlaylistsWidget(Gtk.Grid): """ Show playlist tracks/albums """ __gsignals__ = { 'populated': (GObject.SignalFlags.RUN_FIRST, None, ()) } def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Grid.__init__(self) self.set_row_spacing(5) self.set_orientation(Gtk.Orientation.VERTICAL) self._playlist_ids = playlist_ids self._tracks_left = [] self._tracks_right = [] self._width = None self._orientation = None self._loading = Loading.NONE # Used to block widget2 populate while showing one column self._locked_widget_right = True self._box = Gtk.Grid() self._box.set_vexpand(True) self._box.set_column_homogeneous(True) self._box.show() self.connect('size-allocate', self._on_size_allocate) self._tracks_widget_left = TracksWidget(True) self._tracks_widget_left.set_vexpand(True) self._tracks_widget_right = TracksWidget(True) self._tracks_widget_right.set_vexpand(True) self._tracks_widget_left.connect('activated', self._on_activated) self._tracks_widget_right.connect('activated', self._on_activated) self._tracks_widget_left.show() self._tracks_widget_right.show() self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, [], Gdk.DragAction.MOVE) self.drag_dest_add_text_targets() self.connect('drag-data-received', self._on_drag_data_received) self.add(self._box) def get_id(self): """ Return playlist widget id @return int """ return Type.PLAYLISTS def show_overlay(self, bool): """ No overlay here now """ pass def update_state(self): """ No state to update """ pass def update_cover(self): """ No update cover for now """ pass def get_current_ordinate(self): """ If current track in widget, return it ordinate, @return y as int """ ordinate = None for child in self._tracks_widget_left.get_children() + \ self._tracks_widget_right.get_children(): if child.get_id() == Lp().player.current_track.id: ordinate = child.translate_coordinates(self._box, 0, 0)[1] return ordinate def populate_list_left(self, tracks, pos): """ Populate left list @param track's ids as array of int (not null) @param track position as int @thread safe """ # We reset width here to allow size allocation code to run self._width = None self._tracks_left = list(tracks) GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_left, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track's ids as array of int (not null) @param track position as int @thread safe """ self._tracks_right = list(tracks) # If we are showing only one column, wait for widget1 if self._orientation == Gtk.Orientation.VERTICAL and\ self._locked_widget_right: GLib.timeout_add(100, self.populate_list_right, tracks, pos) else: # We reset width here to allow size allocation code to run self._width = None GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_right, pos) def update_playing_indicator(self): """ Update playing indicator """ self._tracks_widget_left.update_playing(Lp().player.current_track.id) self._tracks_widget_right.update_playing(Lp().player.current_track.id) def stop(self): """ Stop loading """ self._loading = Loading.STOP def append(self, track_id): """ Add track to widget @param track id as int """ self._add_tracks([track_id], self._tracks_widget_right, -1) self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks_left) + 1) def remove(self, track_id): """ Del track from widget @param track id as int """ children = self._tracks_widget_left.get_children() + \ self._tracks_widget_right.get_children() # Clear the widget if track_id is None: for child in children: child.destroy() self._update_tracks() else: for child in children: if child.get_id() == track_id: child.destroy() break self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes( len(self._tracks_left) + 1) ####################### # PRIVATE # ####################### def _add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param pos as int @param previous album id as int """ if self._loading == Loading.STOP: self._loading = Loading.NONE return if not tracks: if widget == self._tracks_widget_right: self._loading |= Loading.RIGHT elif widget == self._tracks_widget_left: self._loading |= Loading.LEFT if self._loading == Loading.ALL: self.emit('populated') self._locked_widget_right = False return track = Track(tracks.pop(0)) row = PlaylistRow(track.id, pos, track.album.id != previous_album_id) row.connect('track-moved', self._on_track_moved) row.show() widget.insert(row, pos) GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, track.album.id) def _update_tracks(self): """ Update tracks based on current widget """ # Recalculate tracks self._tracks_left = [] self._tracks_right = [] for child in self._tracks_widget_left.get_children(): self._tracks_left.append(child.get_id()) for child in self._tracks_widget_right.get_children(): self._tracks_right.append(child.get_id()) def _update_position(self): """ Update widget position """ len_tracks1 = len(self._tracks_left) len_tracks2 = len(self._tracks_right) # Take first track from tracks2 and put it at the end of tracks1 if len_tracks2 > len_tracks1: src = self._tracks_right[0] if self._tracks_left: dst = self._tracks_left[-1] else: dst = -1 self._move_track(dst, src, False) # Take last track of tracks1 and put it at the bottom of tracks2 elif len_tracks1 - 1 > len_tracks2: src = self._tracks_left[-1] if self._tracks_right: dst = self._tracks_right[0] else: dst = -1 self._move_track(dst, src, True) self._update_tracks() def _update_headers(self): """ Update headers for all tracks """ self._tracks_widget_left.update_headers() prev_album_id = None if self._orientation == Gtk.Orientation.VERTICAL: if self._tracks_left: prev_album_id = Track(self._tracks_left[-1]).album.id self._tracks_widget_right.update_headers(prev_album_id) def _move_track(self, dst, src, up): """ Move track from src to row @param dst as int @param src as int @param up as bool @return (dst_widget as TracksWidget, src index as int, dst index as int) """ tracks1_len = len(self._tracks_left) tracks2_len = len(self._tracks_right) if src in self._tracks_left: src_widget = self._tracks_widget_left src_index = self._tracks_left.index(src) - 1 else: src_widget = self._tracks_widget_right src_index = self._tracks_right.index(src) - 1 if tracks1_len == 0 or dst in self._tracks_left: dst_widget = self._tracks_widget_left dst_tracks = self._tracks_left elif tracks2_len == 0 or dst in self._tracks_right: dst_widget = self._tracks_widget_right dst_tracks = self._tracks_right else: return # Remove src from src_widget for child in src_widget.get_children(): if child.get_id() == src: child.destroy() break src_track = Track(src) prev_track = Track() name = escape(src_track.name) index = 0 # Get previous track if dst != -1: for child in dst_widget.get_children(): if child.get_id() == dst: break index += 1 if not up: index += 1 # Get previous track (in dst context) prev_index = dst_tracks.index(dst) if up: prev_index -= 1 prev_track = Track(dst_tracks[prev_index]) # If we are listening to a compilation, prepend artist name if (src_track.album.artist_id == Type.COMPILATIONS or len(src_track.artist_ids) > 1 or src_track.album.artist_id not in src_track.artist_ids): name = "<b>%s</b>\n%s" % (escape(", ".join(src_track.artists)), name) self._tracks_left.insert(index, src_track.id) row = PlaylistRow(src_track.id, index, index == 0 or src_track.album.id != prev_track.album.id) row.connect('track-moved', self._on_track_moved) row.show() dst_widget.insert(row, index) return (src_widget, dst_widget, src_index, index) def _on_drag_data_received(self, widget, context, x, y, data, info, time): """ ONLY HAPPEN IN VERTICAL ORIENTATION Horizontal orientation is handled by TracksWidget @param widget as Gtk.Widget @param context as Gdk.DragContext @param x as int @param y as int @param data as Gtk.SelectionData @param info as int @param time as int """ try: try: child = self._tracks_widget_right.get_children()[-1] except: child = self._tracks_widget_left.get_children()[-1] self._on_track_moved(widget, child.get_id(), int(data.get_text()), False) except: pass def _on_track_moved(self, widget, dst, src, up): """ Move track from src to row Recalculate track position @param widget as TracksWidget @param dst as int @param src as int @param up as bool """ def update_playlist(): # Save playlist in db only if one playlist visible if len(self._playlist_ids) == 1 and self._playlist_ids[0] >= 0: Lp().playlists.clear(self._playlist_ids[0], False) tracks = [] for track_id in self._tracks_left + self._tracks_right: tracks.append(Track(track_id)) Lp().playlists.add_tracks(self._playlist_ids[0], tracks, False) if not (set(self._playlist_ids) - set(Lp().player.get_user_playlist_ids())): Lp().player.update_user_playlist(self._tracks_left + self._tracks_right) (src_widget, dst_widget, src_index, dst_index) = \ self._move_track(dst, src, up) self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks_left) + 1) t = Thread(target=update_playlist) t.daemon = True t.start() def _on_size_allocate(self, widget, allocation): """ Change box max/min children @param widget as Gtk.Widget @param allocation as Gtk.Allocation """ if self._width == allocation.width: return self._width = allocation.width redraw = False if allocation.width < WindowSize.MONSTER: self._box.set_property('valign', Gtk.Align.START) orientation = Gtk.Orientation.VERTICAL else: self._box.set_property('valign', Gtk.Align.FILL) orientation = Gtk.Orientation.HORIZONTAL if orientation != self._orientation: self._orientation = orientation redraw = True self._box.set_orientation(orientation) if redraw: for child in self._box.get_children(): self._box.remove(child) GLib.idle_add(self._box.add, self._tracks_widget_left) GLib.idle_add(self._box.add, self._tracks_widget_right) self._update_headers() def _on_activated(self, widget, track_id): """ On track activation, play track @param widget as TracksWidget @param track as Track """ # Add to queue by default if Lp().player.locked or Lp().player.queued: if track_id in Lp().player.get_queue(): Lp().player.del_from_queue(track_id) else: Lp().player.append_to_queue(track_id) else: Lp().player.load(Track(track_id)) if not Lp().player.is_party(): Lp().player.populate_user_playlist_by_tracks( self._tracks_left + self._tracks_right, self._playlist_ids)
class PlaylistsWidget(Gtk.Grid): """ Show playlist tracks/albums """ __gsignals__ = {"populated": (GObject.SignalFlags.RUN_FIRST, None, ())} def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Grid.__init__(self) self.set_row_spacing(5) self.set_orientation(Gtk.Orientation.VERTICAL) self.__playlist_ids = playlist_ids self.__tracks_left = [] self.__tracks_right = [] self.__width = None self.__orientation = None self.__loading = Loading.NONE # Used to block widget2 populate while showing one column self.__locked_widget_right = True self.__grid = Gtk.Grid() self.__grid.set_vexpand(True) self.__grid.set_column_homogeneous(True) self.__grid.show() self.connect("size-allocate", self.__on_size_allocate) self.__tracks_widget_left = TracksWidget(True) self.__tracks_widget_left.set_vexpand(True) self.__tracks_widget_right = TracksWidget(True) self.__tracks_widget_right.set_vexpand(True) self.__tracks_widget_left.connect("activated", self.__on_activated) self.__tracks_widget_right.connect("activated", self.__on_activated) self.__tracks_widget_left.show() self.__tracks_widget_right.show() self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, [], Gdk.DragAction.MOVE) self.drag_dest_add_text_targets() self.connect("drag-data-received", self.__on_drag_data_received) self.add(self.__grid) @property def id(self): """ Return playlist widget id @return int """ return Type.PLAYLISTS @property def boxes(self): """ @return [Gtk.ListBox] """ return [self.__tracks_widget_left, self.__tracks_widget_right] def set_filter_func(self, func): """ Set filter function """ self.__tracks_widget_left.set_filter_func(func) self.__tracks_widget_right.set_filter_func(func) def show_overlay(self, bool): """ No overlay here now """ pass def update_state(self): """ No state to update """ pass def update_cover(self): """ No update cover for now """ pass def update_allocation(self): """ Update widget allocation """ self.__width = 0 self.__on_size_allocate(self, self.get_allocation()) def get_current_ordinate(self): """ If current track in widget, return it ordinate, @return y as int """ ordinate = None for child in self.__tracks_widget_left.get_children() + \ self.__tracks_widget_right.get_children(): if child.id == Lp().player.current_track.id: ordinate = child.translate_coordinates(self.__grid, 0, 0)[1] return ordinate def populate_list_left(self, tracks, pos): """ Populate left list @param track"s ids as array of int (not null) @param track position as int @thread safe """ # We reset width here to allow size allocation code to run self.__width = None self.__tracks_left = list(tracks) GLib.idle_add(self.__add_tracks, tracks, self.__tracks_widget_left, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track"s ids as array of int (not null) @param track position as int @thread safe """ self.__tracks_right = list(tracks) # If we are showing only one column, wait for widget1 if self.__orientation == Gtk.Orientation.VERTICAL and\ self.__locked_widget_right: GLib.timeout_add(100, self.populate_list_right, tracks, pos) else: # We reset width here to allow size allocation code to run self.__width = None GLib.idle_add(self.__add_tracks, tracks, self.__tracks_widget_right, pos) def update_playing_indicator(self): """ Update playing indicator """ self.__tracks_widget_left.update_playing(Lp().player.current_track.id) self.__tracks_widget_right.update_playing(Lp().player.current_track.id) def update_duration(self, track_id): """ Update duration for current track @param track id as int """ self.__tracks_widget_left.update_duration(track_id) self.__tracks_widget_right.update_duration(track_id) def stop(self): """ Stop loading """ self.__loading = Loading.STOP def insert(self, track_id, pos=-1): """ Add track to widget @param track id as int @param pos as int """ children_len = len(self.__tracks_widget_left.get_children() + self.__tracks_widget_right.get_children()) if pos > children_len / 2: widget = self.__tracks_widget_right pos -= len(self.__tracks_widget_left.get_children()) else: widget = self.__tracks_widget_left self.__add_tracks([track_id], widget, pos) self.__update_tracks() self.__update_position() self.__update_headers() self.__tracks_widget_left.update_indexes(1) self.__tracks_widget_right.update_indexes(len(self.__tracks_left) + 1) def remove(self, track_id): """ Del track from widget @param track id as int """ children = self.__tracks_widget_left.get_children() + \ self.__tracks_widget_right.get_children() # Clear the widget if track_id is None: for child in children: child.destroy() self.__update_tracks() else: for child in children: if child.id == track_id: child.destroy() break self.__update_tracks() self.__update_position() self.__update_headers() self.__tracks_widget_left.update_indexes(1) self.__tracks_widget_right.update_indexes( len(self.__tracks_left) + 1) ####################### # PRIVATE # ####################### def __add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param pos as int @param previous album id as int """ if self.__loading == Loading.STOP: self.__loading = Loading.NONE return if not tracks: if widget == self.__tracks_widget_right: self.__loading |= Loading.RIGHT elif widget == self.__tracks_widget_left: self.__loading |= Loading.LEFT if self.__loading == Loading.ALL: self.emit("populated") self.__locked_widget_right = False return track = Track(tracks.pop(0)) row = PlaylistRow(track.id, pos, track.album.id != previous_album_id) row.connect("track-moved", self.__on_track_moved) row.show() widget.insert(row, pos) GLib.idle_add(self.__add_tracks, tracks, widget, pos + 1, track.album.id) def __update_tracks(self): """ Update tracks based on current widget """ # Recalculate tracks self.__tracks_left = [] self.__tracks_right = [] for child in self.__tracks_widget_left.get_children(): self.__tracks_left.append(child.id) for child in self.__tracks_widget_right.get_children(): self.__tracks_right.append(child.id) def __update_position(self): """ Update widget position """ len_tracks1 = len(self.__tracks_left) len_tracks2 = len(self.__tracks_right) # Take first track from tracks2 and put it at the end of tracks1 if len_tracks2 > len_tracks1: src = self.__tracks_right[0] if self.__tracks_left: dst = self.__tracks_left[-1] else: dst = -1 self.__move_track(dst, src, False) # Take last track of tracks1 and put it at the bottom of tracks2 elif len_tracks1 - 1 > len_tracks2: src = self.__tracks_left[-1] if self.__tracks_right: dst = self.__tracks_right[0] else: dst = -1 self.__move_track(dst, src, True) self.__update_tracks() def __update_headers(self): """ Update headers for all tracks """ self.__tracks_widget_left.update_headers() prev_album_id = None if self.__orientation == Gtk.Orientation.VERTICAL: if self.__tracks_left: prev_album_id = Track(self.__tracks_left[-1]).album.id self.__tracks_widget_right.update_headers(prev_album_id) def __show_spinner(self, widget, track_id): """ Show spinner for widget @param widget as TracksWidget @param track id as int """ track = Track(track_id) if track.is_web: widget.show_spinner(track_id) def __move_track(self, dst, src, up): """ Move track from src to row @param dst as int @param src as int @param up as bool @return (dst_widget as TracksWidget, src index as int, dst index as int) """ tracks1_len = len(self.__tracks_left) tracks2_len = len(self.__tracks_right) if src in self.__tracks_left: src_widget = self.__tracks_widget_left src_index = self.__tracks_left.index(src) - 1 else: src_widget = self.__tracks_widget_right src_index = self.__tracks_right.index(src) - 1 if tracks1_len == 0 or dst in self.__tracks_left: dst_widget = self.__tracks_widget_left dst_tracks = self.__tracks_left elif tracks2_len == 0 or dst in self.__tracks_right: dst_widget = self.__tracks_widget_right dst_tracks = self.__tracks_right else: return # Remove src from src_widget for child in src_widget.get_children(): if child.id == src: child.destroy() break src_track = Track(src) prev_track = Track() name = GLib.markup_escape_text(src_track.name) index = 0 # Get previous track if dst != -1: for child in dst_widget.get_children(): if child.id == dst: break index += 1 if not up: index += 1 # Get previous track (in dst context) prev_index = dst_tracks.index(dst) if up: prev_index -= 1 prev_track = Track(dst_tracks[prev_index]) # If we are listening to a compilation, prepend artist name if (src_track.album.artist_id == Type.COMPILATIONS or len(src_track.artist_ids) > 1 or src_track.album.artist_id not in src_track.artist_ids): name = "<b>%s</b>\n%s" % (GLib.markup_escape_text(", ".join( src_track.artists)), name) self.__tracks_left.insert(index, src_track.id) row = PlaylistRow( src_track.id, index, index == 0 or src_track.album.id != prev_track.album.id) row.connect("track-moved", self.__on_track_moved) row.show() dst_widget.insert(row, index) return (src_widget, dst_widget, src_index, index) def __on_drag_data_received(self, widget, context, x, y, data, info, time): """ ONLY HAPPEN IN VERTICAL ORIENTATION Horizontal orientation is handled by TracksWidget @param widget as Gtk.Widget @param context as Gdk.DragContext @param x as int @param y as int @param data as Gtk.SelectionData @param info as int @param time as int """ try: value = int(data.get_text()) try: child = self.__tracks_widget_right.get_children()[-1] except: child = self.__tracks_widget_left.get_children()[-1] self.__on_track_moved(widget, child.id, value, False) except: if len(self.__playlist_ids) == 1: Lp().playlists.import_uri(self.__playlist_ids[0], data.get_text()) def __on_track_moved(self, widget, dst, src, up): """ Move track from src to row Recalculate track position @param widget as TracksWidget @param dst as int @param src as int @param up as bool """ def update_playlist(): # Save playlist in db only if one playlist visible if len(self.__playlist_ids) == 1 and self.__playlist_ids[0] >= 0: Lp().playlists.clear(self.__playlist_ids[0], False) tracks = [] for track_id in self.__tracks_left + self.__tracks_right: tracks.append(Track(track_id)) Lp().playlists.add_tracks(self.__playlist_ids[0], tracks, False) if not (set(self.__playlist_ids) - set(Lp().player.get_user_playlist_ids())): Lp().player.update_user_playlist(self.__tracks_left + self.__tracks_right) (src_widget, dst_widget, src_index, dst_index) = \ self.__move_track(dst, src, up) self.__update_tracks() self.__update_position() self.__update_headers() self.__tracks_widget_left.update_indexes(1) self.__tracks_widget_right.update_indexes(len(self.__tracks_left) + 1) t = Thread(target=update_playlist) t.daemon = True t.start() def __on_size_allocate(self, widget, allocation): """ Change box max/min children @param widget as Gtk.Widget @param allocation as Gtk.Allocation """ if self.__width == allocation.width: return self.__width = allocation.width redraw = False if allocation.width < WindowSize.MONSTER or\ not Lp().settings.get_value("split-view"): self.__grid.set_property("valign", Gtk.Align.START) orientation = Gtk.Orientation.VERTICAL else: self.__grid.set_property("valign", Gtk.Align.FILL) orientation = Gtk.Orientation.HORIZONTAL if orientation != self.__orientation: self.__orientation = orientation redraw = True self.__grid.set_orientation(orientation) if redraw: for child in self.__grid.get_children(): self.__grid.remove(child) GLib.idle_add(self.__grid.add, self.__tracks_widget_left) GLib.idle_add(self.__grid.add, self.__tracks_widget_right) self.__update_headers() def __on_activated(self, widget, track_id): """ On track activation, play track @param widget as TracksWidget @param track as Track """ # Add to queue by default if Lp().player.locked: if track_id in Lp().player.queue: Lp().player.del_from_queue(track_id) else: Lp().player.append_to_queue(track_id) else: self.__show_spinner(widget, track_id) Lp().player.load(Track(track_id)) if not Lp().player.is_party: Lp().player.populate_user_playlist_by_tracks( self.__tracks_left + self.__tracks_right, self.__playlist_ids)
class PlaylistsWidget(Gtk.Bin): """ Show playlist tracks/albums """ def __init__(self, playlist_ids): """ Init playlist Widget @param playlist ids as [int] """ Gtk.Bin.__init__(self) self._playlist_ids = playlist_ids self._tracks1 = [] self._tracks2 = [] self._width = None self._orientation = None self._stop = False # Used to block widget2 populate while showing one column self._locked_widget2 = True self._box = Gtk.Grid() self._box.set_column_homogeneous(True) self._box.set_property('valign', Gtk.Align.START) self._box.show() self.connect('size-allocate', self._on_size_allocate) self._tracks_widget_left = TracksWidget() self._tracks_widget_right = TracksWidget() self._tracks_widget_left.connect('activated', self._on_activated) self._tracks_widget_right.connect('activated', self._on_activated) self._tracks_widget_left.show() self._tracks_widget_right.show() self.add(self._box) def get_id(self): """ Return playlist widget id @return int """ return Type.PLAYLISTS def show_overlay(self, bool): """ No overlay here now """ pass def update_state(self): """ No state to update """ pass def update_cover(self): """ No update cover for now """ pass def get_current_ordinate(self): """ If current track in widget, return it ordinate, @return y as int """ ordinate = None for child in self._tracks_widget_left.get_children() + \ self._tracks_widget_right.get_children(): if child.get_id() == Lp().player.current_track.id: ordinate = child.translate_coordinates(self._box, 0, 0)[1] return ordinate def populate_list_left(self, tracks, pos): """ Populate left list @param track's ids as array of int (not null) @param track position as int @thread safe """ # We reset width here to allow size allocation code to run self._width = None self._tracks1 = list(tracks) GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_left, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track's ids as array of int (not null) @param track position as int @thread safe """ self._tracks2 = list(tracks) # If we are showing only one column, wait for widget1 if self._orientation == Gtk.Orientation.VERTICAL and\ self._locked_widget2: GLib.timeout_add(100, self.populate_list_right, tracks, pos) else: # We reset width here to allow size allocation code to run self._width = None GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_right, pos) def update_playing_indicator(self): """ Update playing indicator """ self._tracks_widget_left.update_playing(Lp().player.current_track.id) self._tracks_widget_right.update_playing(Lp().player.current_track.id) def stop(self): """ Stop loading """ self._stop = True def append(self, track_id): """ Add track to widget @param track id as int """ self._add_tracks([track_id], self._tracks_widget_right, -1) self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks1) + 1) def remove(self, track_id): """ Del track from widget @param track id as int """ children = self._tracks_widget_left.get_children() + \ self._tracks_widget_right.get_children() # Clear the widget if track_id is None: for child in children: child.destroy() self._update_tracks() else: for child in children: if child.get_id() == track_id: child.destroy() break self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks1) + 1) ####################### # PRIVATE # ####################### def _add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param pos as int @param previous album id as int """ if not tracks or self._stop: if widget == self._tracks_widget_right: self._stop = False else: self._locked_widget2 = False return track = Track(tracks.pop(0)) row = PlaylistRow(track.id, pos, track.album.id != previous_album_id) row.connect('track-moved', self._on_track_moved) row.show() widget.insert(row, pos) GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, track.album.id) def _update_tracks(self): """ Update tracks based on current widget """ # Recalculate tracks self._tracks1 = [] self._tracks2 = [] for child in self._tracks_widget_left.get_children(): self._tracks1.append(child.get_id()) for child in self._tracks_widget_right.get_children(): self._tracks2.append(child.get_id()) def _update_position(self): """ Update widget position """ len_tracks1 = len(self._tracks1) len_tracks2 = len(self._tracks2) # Take first track from tracks2 and put it at the end of tracks1 if len_tracks2 > len_tracks1: src = self._tracks2[0] if self._tracks1: dst = self._tracks1[-1] else: dst = -1 self._move_track(dst, src, False) # Take last track of tracks1 and put it at the bottom of tracks2 elif len_tracks1 - 1 > len_tracks2: src = self._tracks1[-1] if self._tracks2: dst = self._tracks2[0] else: dst = -1 self._move_track(dst, src, True) self._update_tracks() def _update_headers(self): """ Update headers for all tracks """ self._tracks_widget_left.update_headers() prev_album_id = None if self._orientation == Gtk.Orientation.VERTICAL: if self._tracks1: prev_album_id = Track(self._tracks1[-1]).album.id self._tracks_widget_right.update_headers(prev_album_id) def _move_track(self, dst, src, up): """ Move track from src to row @param dst as int @param src as int @param up as bool @return (dst_widget as TracksWidget, src index as int, dst index as int) """ tracks1_len = len(self._tracks1) tracks2_len = len(self._tracks2) if src in self._tracks1: src_widget = self._tracks_widget_left src_index = self._tracks1.index(src) - 1 else: src_widget = self._tracks_widget_right src_index = self._tracks2.index(src) - 1 if tracks1_len == 0 or dst in self._tracks1: dst_widget = self._tracks_widget_left dst_tracks = self._tracks1 elif tracks2_len == 0 or dst in self._tracks2: dst_widget = self._tracks_widget_right dst_tracks = self._tracks2 else: return # Remove src from src_widget for child in src_widget.get_children(): if child.get_id() == src: child.destroy() break src_track = Track(src) prev_track = Track() name = escape(src_track.name) index = 0 # Get previous track if dst != -1: for child in dst_widget.get_children(): if child.get_id() == dst: break index += 1 if not up: index += 1 # Get previous track (in dst context) prev_index = dst_tracks.index(dst) if up: prev_index -= 1 prev_track = Track(dst_tracks[prev_index]) # If we are listening to a compilation, prepend artist name if (src_track.album.artist_id == Type.COMPILATIONS or len(src_track.artist_ids) > 1 or src_track.album.artist_id not in src_track.artist_ids): name = "<b>%s</b>\n%s" % (escape(", ".join(src_track.artists)), name) self._tracks1.insert(index, src_track.id) row = PlaylistRow(src_track.id, index, index == 0 or src_track.album.id != prev_track.album.id) row.connect('track-moved', self._on_track_moved) row.show() dst_widget.insert(row, index) return (src_widget, dst_widget, src_index, index) def _on_track_moved(self, widget, dst, src, up): """ Move track from src to row Recalculate track position @param widget as TracksWidget @param dst as int @param src as int @param up as bool """ def update_playlist(): # Save playlist in db only if one playlist visible if len(self._playlist_ids) == 1 and self._playlist_ids[0] >= 0: Lp().playlists.clear(self._playlist_ids[0], False) tracks = [] for track_id in self._tracks1 + self._tracks2: tracks.append(Track(track_id)) Lp().playlists.add_tracks(self._playlist_ids[0], tracks, False) if not (set(self._playlist_ids) - set(Lp().player.get_user_playlist_ids())): Lp().player.update_user_playlist(self._tracks1 + self._tracks2) (src_widget, dst_widget, src_index, dst_index) = \ self._move_track(dst, src, up) self._update_tracks() self._update_position() self._update_headers() self._tracks_widget_left.update_indexes(1) self._tracks_widget_right.update_indexes(len(self._tracks1) + 1) t = Thread(target=update_playlist) t.daemon = True t.start() def _on_size_allocate(self, widget, allocation): """ Change box max/min children @param widget as Gtk.Widget @param allocation as Gtk.Allocation """ if self._width == allocation.width: return self._width = allocation.width redraw = False if allocation.width < WindowSize.MONSTER: orientation = Gtk.Orientation.VERTICAL else: orientation = Gtk.Orientation.HORIZONTAL if orientation != self._orientation: self._orientation = orientation redraw = True self._box.set_orientation(orientation) if redraw: for child in self._box.get_children(): self._box.remove(child) GLib.idle_add(self._box.add, self._tracks_widget_left) GLib.idle_add(self._box.add, self._tracks_widget_right) self._update_headers() def _on_activated(self, widget, track_id): """ On track activation, play track @param widget as TracksWidget @param track as Track """ Lp().player.load(Track(track_id)) if not Lp().player.is_party(): Lp().player.populate_user_playlist_by_tracks(self._tracks1 + self._tracks2, self._playlist_ids)
class PlaylistWidget(Gtk.Bin): """ Show playlist tracks/albums """ def __init__(self, playlist_id, playlist_name): """ Init playlist Widget @param playlist id as int @param playlist name as str """ Gtk.Bin.__init__(self) self._playlist_id = playlist_id self._playlist_name = playlist_name self._tracks1 = [] self._tracks2 = [] self._stop = False self._main_widget = Gtk.Grid() self._main_widget.set_property('margin', 10) self._main_widget.set_property('column-spacing', 10) self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self._stack = Gtk.Stack() self._stack.set_transition_duration(250) self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self._stack.show() spinner = Gtk.Spinner() spinner.start() spinner.show() self._stack.add(spinner) self._stack.add(self._main_widget) self._stack.set_visible_child(spinner) self.add(self._stack) def populate_list_left(self, tracks, pos): """ Populate left list @param track's ids as array of int @param track position as int @thread safe """ GLib.idle_add(self._stack.set_visible_child, self._main_widget) self._stop = False GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos) def populate_list_right(self, tracks, pos): """ Populate right list @param track's ids as array of int @param track position as int @thread safe """ self._stop = False GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos) def update_playing_indicator(self): """ Update playing indicator """ self._tracks_widget1.update_playing(Lp.player.current_track.id) self._tracks_widget2.update_playing(Lp.player.current_track.id) def stop(self): """ Stop loading """ self._stop = True def clear(self): """ Clear tracks """ self._tracks = [] for child in self._tracks_widget1.get_children(): child.destroy() for child in self._tracks_widget2.get_children(): child.destroy() ####################### # PRIVATE # ####################### def _add_tracks(self, tracks, widget, pos, previous_album_id=None): """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int @param previous album id as int """ if not tracks or self._stop: return track = Track(tracks.pop(0)) name = escape(track.name) album = track.album if track.id is None: GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, previous_album_id) return # If we are listening to a compilation, prepend artist name if (album.artist_id == Type.COMPILATIONS or len(track.artist_ids) > 1 or album.artist_id not in track.artist_ids): name = "<b>%s</b>\n%s" % (escape(track.artist_names), name) if widget == self._tracks_widget1: self._tracks1.append(track) else: self._tracks2.append(track) if album.id != previous_album_id: widget.add_album(track.id, album.id, pos, name, track.duration, None) else: widget.add_album(track.id, None, pos, name, track.duration, None) GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, album.id) def _on_activated(self, widget, track_id, playlist_name): """ On track activation, play track @param widget as TracksWidget @param track as Track @param playlist name as str """ if Lp.player.is_party(): Lp.player.load(Track(track_id)) else: track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2, track_id) Lp.player.set_user_playlist_id(self._playlist_id) if track is not None: Lp.player.load(track)
class PlaylistWidget(Gtk.Bin): """ Init playlist Widget @param playlist name as str """ def __init__(self, playlist_name): Gtk.Bin.__init__(self) self._playlist_name = playlist_name self._tracks = [] self._main_widget = Gtk.Grid() self._main_widget.show() self._tracks_widget1 = TracksWidget(False) self._tracks_widget2 = TracksWidget(False) self._tracks_widget1.connect('activated', self._on_activated, playlist_name) self._tracks_widget2.connect('activated', self._on_activated, playlist_name) self._tracks_widget1.show() self._tracks_widget2.show() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) size_group.add_widget(self._tracks_widget1) size_group.add_widget(self._tracks_widget2) self._main_widget.add(self._tracks_widget1) self._main_widget.add(self._tracks_widget2) self.add(self._main_widget) """ Populate list one, thread safe @param track's ids as array of int @param track position as int """ def populate_list_one(self, tracks, pos): GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos) """ Populate list two, thread safe @param track's ids as array of int @param track position as int """ def populate_list_two(self, tracks, pos): GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos) """ Update playing indicator """ def update_playing_indicator(self): self._tracks_widget1.update_playing(Objects.player.current.id) self._tracks_widget2.update_playing(Objects.player.current.id) """ Clear tracks """ def clear(self): self._tracks = [] for child in self._tracks_widget1.get_children(): child.destroy() for child in self._tracks_widget2.get_children(): child.destroy() ####################### # PRIVATE # ####################### """ Add tracks to list @param tracks id as array of [int] @param widget TracksWidget @param track position as int """ def _add_tracks(self, tracks, widget, pos): if not tracks: return track_id = tracks.pop(0) if track_id == -1: return (title, filepath, length, album_id) =\ Objects.tracks.get_infos(track_id) artist_name = "" for artist_id in Objects.tracks.get_artist_ids(track_id): artist_name += translate_artist_name( Objects.artists.get_name(artist_id)) + ", " title = "<b>%s</b>\n%s" % (escape(artist_name[:-2]), escape(title)) widget.add_track(track_id, pos, title, length, None, True) GLib.idle_add(self._add_tracks, tracks, widget, pos+1) """ On track activation, play track @param widget as TracksWidget @param track id as int @param playlist name as str """ def _on_activated(self, widget, track_id, playlist_name): if not Objects.player.is_party(): if not self._tracks: self._tracks = Objects.playlists.get_tracks_id(playlist_name) Objects.player.set_user_playlist(self._tracks, track_id) Objects.player.load(track_id)