Beispiel #1
0
 def __add_track(self, track):
     """
         Add track to model
         @param track as Track
         @param filepath as string
     """
     if track.uri == Lp().player.current_track.uri:
         self.__model.append((track.uri, 'media-playback-start-symbolic',
                             track.artist, track.title,
                             seconds_to_string(track.duration)))
     else:
         self.__model.append((track.uri, '', track.artist, track.title,
                             seconds_to_string(track.duration)))
Beispiel #2
0
    def on_current_changed(self, player):
        """
            Update scale on current changed
            @param player as Player
        """
        if self.__show_volume_control:
            return
        self._progress.clear_marks()
        if player.current_track.id is None:
            self._progress.set_sensitive(False)
            self._total_time_label.set_text("")
            self._timelabel.set_text("")
            return

        self._progress.set_value(0.0)
        self._timelabel.set_text("0:00")
        if player.current_track.id == Type.RADIOS:
            self._progress.set_sensitive(False)
            self._total_time_label.set_text("")
            self._progress.set_range(0.0, 0.0)
        else:
            self._progress.set_sensitive(True)
            self._progress.set_range(0.0, player.current_track.duration)
            self._total_time_label.set_text(
                seconds_to_string(player.current_track.duration))
Beispiel #3
0
 def add_track(self, track_id, num, title, length, pos, show_cover=False):
     track_row = TrackRow()
     track_row.show_widget('cover', show_cover)
     track_row.show_widget('menu', self._show_menu)
     if Objects.player.current.id == track_id:
         track_row.show_widget('icon', True)
     if pos:
         track_row.set_label(
                         'num',
                         '''<span foreground="%s"\
                         font_desc="Bold">%s</span>''' %\
                         (Objects.window.get_background_color().to_string(),
                          str(pos)))
     else:
         track_row.set_label('num', str(num))
     track_row.set_number(num)
     track_row.set_label('title', title)
     track_row.set_label('duration', seconds_to_string(length))
     track_row.set_object_id(track_id)
     if show_cover:
         album_id = Objects.tracks.get_album_id(track_id)
         pixbuf = Objects.art.get(album_id, ArtSize.MEDIUM)
         track_row.set_cover(pixbuf)
         del pixbuf
     track_row.show()
     self.add(track_row)
Beispiel #4
0
 def update_duration(self):
     """
         Update track duration
     """
     self._track.reset("duration")
     duration = seconds_to_string(self._track.duration)
     self._duration_label.set_label(duration)
Beispiel #5
0
 def add_album(self, track_id, album, num, title, length, pos):
     """
         Add album row to the list
         @param track id as int
         @param album as album (None)
         @param track number as int
         @param title as str
         @param length as str
         @param pos as int
         @param show cover as bool
     """
     album_row = AlbumRow(self._show_loved)
     album_row.show_indicator(Lp().player.current_track.id == track_id,
                              utils.is_loved(track_id))
     if pos:
         album_row.set_num_label(
             '''<span foreground="%s"
             font_desc="Bold">%s</span>''' %
             (rgba_to_hex(Lp().window.get_selected_color()), str(pos)))
     elif num > 0:
         album_row.set_num_label(str(num))
     album_row.set_number(num)
     album_row.set_title_label(title)
     album_row.set_duration_label(seconds_to_string(length))
     album_row.set_object_id(track_id)
     if album is not None:
         album_row.set_album_and_artist(album.id)
         surface = Lp().art.get_album_artwork(
             album, ArtSize.MEDIUM * album_row.get_scale_factor())
         album_row.set_cover(surface, Lp().albums.get_name(album.id))
         del surface
         album_row.show_header()
     album_row.show()
     self.add(album_row)
Beispiel #6
0
 def add_track(self, track_id, num, title, length, pos):
     """
         Add track to list
         @param track id as int
         @param track number as int
         @param title as str
         @param length as str
         @param pos as int
         @param show cover as bool
     """
     track_row = TrackRow()
     track_row.show_menu(self._show_menu)
     if Lp.player.current_track.id == track_id:
         track_row.show_icon(True)
     if pos:
         track_row.set_num_label(
             '''<span foreground="%s"
             font_desc="Bold">%s</span>''' %
             (rgba_to_hex(Lp.window.get_selected_color()), str(pos)))
     elif num > 0:
         track_row.set_num_label(str(num))
     track_row.set_number(num)
     track_row.set_title_label(title)
     track_row.set_duration_label(seconds_to_string(length))
     track_row.set_object_id(track_id)
     track_row.show()
     self.add(track_row)
Beispiel #7
0
 def update_duration(self):
     """
         Update duration for row
     """
     # Get a new track to get new duration (cache)
     track = Track(self._track.id)
     self._duration_label.set_text(seconds_to_string(track.duration))
    def on_current_changed(self, player):
        """
            Update scale on current changed
            @param player as Player
        """
        style_context = self._progress.get_style_context()
        style_context.remove_class("youtube-scale")
        if player.current_track.id is None:
            self._progress.set_sensitive(False)
            self._total_time_label.set_text("")
            self._timelabel.set_text("")
            return

        self._progress.set_value(0.0)
        self._timelabel.set_text("0:00")
        if player.current_track.id == Type.RADIOS:
            self._progress.set_sensitive(False)
            self._progress.set_opacity(0)
            self._timelabel.set_opacity(0)
            self._total_time_label.set_opacity(0)
            self._progress.set_range(0.0, 0.0)
        else:
            if player.current_track.mtime <= 0:
                style_context.add_class("youtube-scale")
            self._progress.set_sensitive(True)
            self._progress.set_opacity(1)
            self._timelabel.set_opacity(1)
            self._total_time_label.set_opacity(1)
            self._progress.set_range(0.0, player.current_track.duration)
            self._total_time_label.set_text(
                seconds_to_string(player.current_track.duration))
Beispiel #9
0
 def _update_position(self, value=None):
     if not self._seeking:
         if value is None:
             value = Objects.player.get_position_in_track() / 1000000
         self._progress.set_value(value)
         self._timelabel.set_text(seconds_to_string(value / 60))
     return True
Beispiel #10
0
    def _on_current_changed(self, player):
        """
            Update View for current track
                - Cover
                - artist/title
                - reset progress bar
                - update time/total labels
            @param player as Player
        """
        if player.current_track.id is not None:
            if Lp.player.current_track.id == Type.RADIOS:
                self._timelabel.hide()
                self._total_time_label.hide()
                self._progress.hide()
                surface = Lp.art.get_radio(player.current_track.artist,
                                           ArtSize.MONSTER)
            elif player.current_track.id == Type.EXTERNALS:
                art = Lp.art.get_cover_for_uri(player.current_track.uri,
                                               ArtSize.MONSTER)
            else:
                self._timelabel.show()
                self._total_time_label.show()
                self._progress.show()
                surface = Lp.art.get_album(player.current_track.album_id,
                                           ArtSize.MONSTER)
            self._cover.set_from_surface(surface)
            del surface

            album = player.current_track.album.name
            if player.current_track.year != '':
                album += " (%s)" % player.current_track.year
            self._title.set_text(player.current_track.title)
            self._artist.set_text(player.current_track.artist)
            self._album.set_text(album)
            self._progress.set_value(1.0)
            self._progress.set_range(0.0, player.current_track.duration * 60)
            self._total_time_label.set_text(
                seconds_to_string(player.current_track.duration))
            self._timelabel.set_text("0:00")

            # Can add a \n in markup
            # GTK bug => https://bugzilla.gnome.org/show_bug.cgi?id=749965
            prev_artist = escape(player.prev_track.artist)
            prev_title = escape(player.prev_track.title)
            next_artist = escape(player.next_track.artist)
            next_title = escape(player.next_track.title)
            self._next_btn.set_tooltip_markup("<b>%s</b> - %s" %
                                              (next_artist, next_title))
            self._prev_btn.set_tooltip_markup("<b>%s</b> - %s" %
                                              (prev_artist, prev_title))

            # Do not show next popover non internal tracks as
            # tags will be readed on the fly
            if player.next_track.id >= 0:
                self._next_popover.update()
                self._next_popover.show()
            else:
                self._next_popover.hide()
Beispiel #11
0
 def __init__(self, rowid, num):
     """
         Init row widgets
         @param rowid as int
         @param num as int
         @param show loved as bool
     """
     # We do not use Gtk.Builder for speed reasons
     Gtk.ListBoxRow.__init__(self)
     self.set_sensitive(False)
     self._track = Track(rowid)
     self._number = num
     self._indicator = IndicatorWidget(self._track.id)
     self.set_indicator(Lp().player.current_track.id == self._track.id,
                        utils.is_loved(self._track.id))
     self.set_sensitive(True)
     self._row_widget = Gtk.EventBox()
     self._row_widget.connect('button-press-event', self._on_button_press)
     self._row_widget.connect('enter-notify-event', self._on_enter_notify)
     self._grid = Gtk.Grid()
     self._grid.set_column_spacing(5)
     self._row_widget.add(self._grid)
     self._title_label = Gtk.Label.new(self._track.formated_name())
     self._title_label.set_use_markup(True)
     self._title_label.set_property('has-tooltip', True)
     self._title_label.connect('query-tooltip',
                               self._on_title_query_tooltip)
     self._title_label.set_property('hexpand', True)
     self._title_label.set_property('halign', Gtk.Align.START)
     self._title_label.set_ellipsize(Pango.EllipsizeMode.END)
     self._duration_label = Gtk.Label.new(
         seconds_to_string(self._track.duration))
     self._duration_label.get_style_context().add_class('dim-label')
     self._num_label = Gtk.Label()
     self._num_label.set_ellipsize(Pango.EllipsizeMode.END)
     self._num_label.set_property('valign', Gtk.Align.CENTER)
     self._num_label.set_width_chars(4)
     self._num_label.get_style_context().add_class('dim-label')
     self.update_num_label()
     self._menu_image = Gtk.Image.new()
     self._menu_image.set_opacity(0.2)
     self._menu_button = Gtk.Button.new()
     self._menu_button.set_relief(Gtk.ReliefStyle.NONE)
     self._menu_button.get_style_context().add_class('menu-button')
     self._menu_button.get_style_context().add_class('track-menu-button')
     self._menu_button.set_image(self._menu_image)
     self._menu_button.connect('clicked', self._on_button_clicked)
     self._grid.add(self._num_label)
     self._grid.add(self._title_label)
     self._grid.add(self._duration_label)
     # TODO Remove this later
     if Gtk.get_minor_version() > 16:
         self._grid.add(self._menu_button)
     else:
         self.connect('map', self._on_map)
     self.add(self._row_widget)
     self.get_style_context().add_class('trackrow')
Beispiel #12
0
 def __on_duration_changed(self, player, track_id):
     """
         Update duration
         @param player as Player
         @param track id as int
     """
     if track_id == player.current_track.id:
         self._progress.set_range(0.0, player.current_track.duration)
         self._total_time_label.set_text(
             seconds_to_string(player.current_track.duration))
Beispiel #13
0
 def _update_position(self, value=None):
     """
         Update progress bar position
         @param value as int
     """
     if not self._seeking and self._progress.is_visible():
         if value is None:
             value = Lp.player.get_position_in_track() / 1000000
         self._progress.set_value(value)
         self._timelabel.set_text(seconds_to_string(value / 60))
     return True
Beispiel #14
0
 def _update_position(self, value=None):
     """
         Update progress bar position
         @param value as int
     """
     if not self._seeking and Lp().player.current_track.id != Type.RADIOS:
         if value is None and Lp().player.get_status() != Gst.State.PAUSED:
             value = Lp().player.get_position_in_track()/1000000
         if value is not None:
             self._progress.set_value(value)
             self._timelabel.set_text(seconds_to_string(value/60))
     return True
 def update_position(self, value=None):
     """
         Update progress bar position
         @param value as int
     """
     if not self.__seeking:
         if value is None and App().player.get_status() != Gst.State.PAUSED:
             value = App().player.position / Gst.SECOND
         if value is not None and value >= 0:
             self._progress.set_value(value)
             self._timelabel.set_text(seconds_to_string(value))
     return True
Beispiel #16
0
    def _on_current_changed(self, player):
        if player.current.id is None:
            self._infobox.get_window().set_cursor(
                Gdk.Cursor(Gdk.CursorType.LEFT_PTR))
            self._cover.hide()
            self._timelabel.hide()
            self._total_time_label.hide()
            self._progress.set_value(0.0)
            self._progress.set_sensitive(False)
            self._prev_btn.set_sensitive(False)
            self._play_btn.set_sensitive(False)
            self._next_btn.set_sensitive(False)
            self._change_play_btn_status(self._play_image, _("Play"))
            self._title_label.hide()
            self._artist_label.hide()
            if Objects.player.is_party():
                self._activate_party_button(None, None)
        else:
            self._prev_btn.set_sensitive(True)
            self._play_btn.set_sensitive(True)
            self._next_btn.set_sensitive(True)
            self._infobox.get_window().set_cursor(
                Gdk.Cursor(Gdk.CursorType.HAND1))
            art = Objects.art.get(player.current.album_id, ArtSize.SMALL)
            if art:
                self._cover.set_from_pixbuf(art)
                self._cover.show()
            else:
                self._cover.hide()

            self._title_label.show()
            self._title_label.set_markup("<span font_desc='Sans 10.5'>"
                                         "%s</span>" %
                                         escape(player.current.title))
            self._artist_label.show()
            self._artist_label.set_markup("<span font_desc='Sans 10.5'>"
                                          "%s</span>" %
                                          escape(player.current.artist))
            self._progress.set_value(0.0)
            self._progress.set_range(0.0, player.current.duration * 60)
            self._total_time_label.set_text(
                seconds_to_string(player.current.duration))
            self._total_time_label.show()
            self._timelabel.set_text("0:00")
            self._timelabel.show()
Beispiel #17
0
 def on_current_changed(self, player):
     """
         Update scale on current changed
         @param player as Player
     """
     if player.current_track.id != Type.RADIOS:
         self._progress.set_sensitive(player.current_track.id is not None)
     self._progress.set_value(0.0)
     if player.current_track.id == Type.RADIOS:
         self._progress.set_sensitive(False)
         self._total_time_label.set_text('')
         self._timelabel.set_text('')
         self._progress.set_range(0.0, 0.0)
     else:
         self._progress.set_range(0.0, player.current_track.duration * 60)
         self._total_time_label.set_text(
             seconds_to_string(player.current_track.duration))
         self._timelabel.set_text("0:00")
Beispiel #18
0
 def _update_position(self, value=None):
     """
         Update progress bar position
         @param value as int
     """
     if self._show_volume_control:
         if value is None:
             value = Lp().player.volume
         self._progress.set_value(value)
         volume = str(int(value * 100)) + " %"
         self._total_time_label.set_text(volume)
     elif not self.__seeking:
         if value is None and Lp().player.get_status() != Gst.State.PAUSED:
             value = Lp().player.position / Gst.SECOND
         if value is not None:
             self._progress.set_value(value)
             self._timelabel.set_text(seconds_to_string(value))
     return True
Beispiel #19
0
    def _on_current_changed(self, player):
        if player.current.id is None:
            pass  # Impossible as we force play on show
        else:
            art = Objects.art.get(player.current.album_id, ArtSize.MONSTER)
            if art:
                self._cover.set_from_pixbuf(art)
                self._cover.show()
            else:
                self._cover.hide()

            self._title.set_text(player.current.title)
            self._artist.set_text(player.current.artist)
            self._album.set_text(player.current.album)
            self._progress.set_value(1.0)
            self._progress.set_range(0.0, player.current.duration * 60)
            self._total_time_label.set_text(
                seconds_to_string(player.current.duration))
            self._timelabel.set_text("0:00")
Beispiel #20
0
 def __init__(self, track, album_artist_ids, view_type):
     """
         Init row widgets
         @param track as Track
         @param album_artist_ids as [int]
         @param view_type as ViewType
     """
     # We do not use Gtk.Builder for speed reasons
     Gtk.ListBoxRow.__init__(self)
     self._view_type = view_type
     self._artists_label = None
     self._track = track
     self.__filtered = False
     self.__next_row = None
     self.__previous_row = None
     self._indicator = IndicatorWidget(self, view_type)
     self._row_widget = Gtk.EventBox()
     self._row_widget.connect("destroy", self._on_destroy)
     self.__gesture = Gtk.GestureLongPress.new(self._row_widget)
     self.__gesture.connect("pressed", self.__on_gesture_pressed)
     self.__gesture.connect("end", self.__on_gesture_end)
     # We want to get release event after gesture
     self.__gesture.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
     self.__gesture.set_button(0)
     self._grid = Gtk.Grid()
     self._grid.set_property("valign", Gtk.Align.CENTER)
     self._grid.set_column_spacing(5)
     self._row_widget.add(self._grid)
     self._title_label = Gtk.Label.new(
         GLib.markup_escape_text(self._track.name))
     self._title_label.set_use_markup(True)
     self._title_label.set_property("has-tooltip", True)
     self._title_label.connect("query-tooltip", on_query_tooltip)
     self._title_label.set_property("hexpand", True)
     self._title_label.set_property("halign", Gtk.Align.START)
     self._title_label.set_property("xalign", 0)
     self._title_label.set_ellipsize(Pango.EllipsizeMode.END)
     featuring_artist_ids = track.get_featuring_artist_ids(album_artist_ids)
     if featuring_artist_ids:
         artists = []
         for artist_id in featuring_artist_ids:
             artists.append(App().artists.get_name(artist_id))
         self._artists_label = Gtk.Label.new(
             GLib.markup_escape_text(", ".join(artists)))
         self._artists_label.set_use_markup(True)
         self._artists_label.set_property("has-tooltip", True)
         self._artists_label.connect("query-tooltip", on_query_tooltip)
         self._artists_label.set_property("hexpand", True)
         self._artists_label.set_property("halign", Gtk.Align.END)
         self._artists_label.set_ellipsize(Pango.EllipsizeMode.END)
         self._artists_label.set_opacity(0.3)
         self._artists_label.set_margin_end(5)
         self._artists_label.show()
     duration = seconds_to_string(self._track.duration)
     self._duration_label = Gtk.Label.new(duration)
     self._duration_label.get_style_context().add_class("dim-label")
     self._num_label = Gtk.Label.new()
     self._num_label.set_ellipsize(Pango.EllipsizeMode.END)
     self._num_label.set_width_chars(4)
     self._num_label.get_style_context().add_class("dim-label")
     self.update_number_label()
     self._grid.add(self._num_label)
     self._grid.add(self._title_label)
     if self._artists_label is not None:
         self._grid.add(self._artists_label)
     self._grid.add(self._duration_label)
     if self._view_type & ViewType.DND and\
             self._view_type & ViewType.POPOVER:
         self.__action_button = Gtk.Button.new_from_icon_name(
             "list-remove-symbolic", Gtk.IconSize.MENU)
         self.__action_button.set_tooltip_text(_("Remove from playback"))
     elif not self._view_type & (ViewType.POPOVER | ViewType.SEARCH):
         self.__action_button = Gtk.Button.new_from_icon_name(
             "view-more-symbolic", Gtk.IconSize.MENU)
     else:
         self.__action_button = None
     if self.__action_button is not None:
         self.__action_button.set_margin_end(MARGIN_SMALL)
         self.__action_button.connect("button-release-event",
                                      self.__on_action_button_release_event)
         self.__action_button.set_relief(Gtk.ReliefStyle.NONE)
         context = self.__action_button.get_style_context()
         context.add_class("menu-button")
         context.add_class("track-menu-button")
         self._grid.add(self.__action_button)
     else:
         self._duration_label.set_margin_end(MARGIN_SMALL)
     self.add(self._row_widget)
     self.set_indicator(self._get_indicator_type())
     self.update_duration()
Beispiel #21
0
 def __init__(self, rowid, num):
     """
         Init row widgets
         @param rowid as int
         @param num as int
         @param show loved as bool
     """
     # We do not use Gtk.Builder for speed reasons
     Gtk.ListBoxRow.__init__(self)
     self._artists_label = None
     self._track = Track(rowid)
     self.__number = num
     self.__preview_timeout_id = None
     self.__context_timeout_id = None
     self.__context = None
     self._indicator = IndicatorWidget(self._track.id)
     self.set_indicator(Lp().player.current_track.id == self._track.id,
                        utils.is_loved(self._track.id))
     self._row_widget = Gtk.EventBox()
     self._row_widget.connect("button-press-event", self.__on_button_press)
     self._row_widget.connect("enter-notify-event", self.__on_enter_notify)
     self._row_widget.connect("leave-notify-event", self.__on_leave_notify)
     self._grid = Gtk.Grid()
     self._grid.set_column_spacing(5)
     self._row_widget.add(self._grid)
     self._title_label = Gtk.Label.new(self._track.name)
     self._title_label.set_property("has-tooltip", True)
     self._title_label.connect("query-tooltip", self.__on_query_tooltip)
     self._title_label.set_property("hexpand", True)
     self._title_label.set_property("halign", Gtk.Align.START)
     self._title_label.set_ellipsize(Pango.EllipsizeMode.END)
     if self._track.non_album_artists:
         self._artists_label = Gtk.Label.new(
             GLib.markup_escape_text(", ".join(
                 self._track.non_album_artists)))
         self._artists_label.set_use_markup(True)
         self._artists_label.set_property("has-tooltip", True)
         self._artists_label.connect("query-tooltip",
                                     self.__on_query_tooltip)
         self._artists_label.set_property("hexpand", True)
         self._artists_label.set_property("halign", Gtk.Align.END)
         self._artists_label.set_ellipsize(Pango.EllipsizeMode.END)
         self._artists_label.set_opacity(0.3)
         self._artists_label.set_margin_end(5)
         self._artists_label.show()
     self._duration_label = Gtk.Label.new(
         seconds_to_string(self._track.duration))
     self._duration_label.get_style_context().add_class("dim-label")
     self._num_label = Gtk.Label()
     self._num_label.set_ellipsize(Pango.EllipsizeMode.END)
     self._num_label.set_property("valign", Gtk.Align.CENTER)
     self._num_label.set_width_chars(4)
     self._num_label.get_style_context().add_class("dim-label")
     self.update_num_label()
     self.__menu_button = Gtk.Button.new()
     # Here a hack to make old Gtk version support min-height css attribute
     # min-height = 24px, borders = 2px, we set directly on stack
     # min-width = 24px, borders = 2px, padding = 8px
     self.__menu_button.set_size_request(34, 26)
     self.__menu_button.set_relief(Gtk.ReliefStyle.NONE)
     self.__menu_button.get_style_context().add_class("menu-button")
     self.__menu_button.get_style_context().add_class("track-menu-button")
     self._grid.add(self._num_label)
     self._grid.add(self._title_label)
     if self._artists_label is not None:
         self._grid.add(self._artists_label)
     self._grid.add(self._duration_label)
     self._grid.add(self.__menu_button)
     self.add(self._row_widget)
     self.get_style_context().add_class("trackrow")
Beispiel #22
0
 def __init__(self, track, list_type):
     """
         Init row widgets
         @param track as Track
         @param list_type as RowListType
     """
     # We do not use Gtk.Builder for speed reasons
     Gtk.ListBoxRow.__init__(self)
     self._list_type = list_type
     self._artists_label = None
     self._track = track
     self.__preview_timeout_id = None
     self.__context_timeout_id = None
     self.__context = None
     self._indicator = IndicatorWidget(self, list_type)
     # We do not use set_indicator() here, we do not want widget to be
     # populated
     if App().player.current_track.id == self._track.id:
         self._indicator.play()
     elif self._track.loved:
         self._indicator.loved(self._track.loved)
     self._row_widget = Gtk.EventBox()
     self._row_widget.connect("destroy", self._on_destroy)
     self._row_widget.connect("button-release-event",
                              self.__on_button_release_event)
     self._row_widget.connect("enter-notify-event",
                              self.__on_enter_notify_event)
     self._row_widget.connect("leave-notify-event",
                              self.__on_leave_notify_event)
     self._grid = Gtk.Grid()
     self._grid.set_column_spacing(5)
     self._row_widget.add(self._grid)
     self._title_label = Gtk.Label.new(self._track.name)
     self._title_label.set_property("has-tooltip", True)
     self._title_label.connect("query-tooltip",
                               self.__on_query_tooltip)
     self._title_label.set_property("hexpand", True)
     self._title_label.set_property("halign", Gtk.Align.START)
     self._title_label.set_property("xalign", 0)
     self._title_label.set_ellipsize(Pango.EllipsizeMode.END)
     featuring_artist_ids = track.featuring_artist_ids
     if featuring_artist_ids:
         artists = []
         for artist_id in featuring_artist_ids:
             artists.append(App().artists.get_name(artist_id))
         self._artists_label = Gtk.Label.new(GLib.markup_escape_text(
             ", ".join(artists)))
         self._artists_label.set_use_markup(True)
         self._artists_label.set_property("has-tooltip", True)
         self._artists_label.connect("query-tooltip",
                                     self.__on_query_tooltip)
         self._artists_label.set_property("hexpand", True)
         self._artists_label.set_property("halign", Gtk.Align.END)
         self._artists_label.set_ellipsize(Pango.EllipsizeMode.END)
         self._artists_label.set_opacity(0.3)
         self._artists_label.set_margin_end(5)
         self._artists_label.show()
     self._duration_label = Gtk.Label.new(
         seconds_to_string(self._track.duration))
     self._duration_label.get_style_context().add_class("dim-label")
     self._num_label = Gtk.Label()
     self._num_label.set_ellipsize(Pango.EllipsizeMode.END)
     self._num_label.set_property("valign", Gtk.Align.CENTER)
     self._num_label.set_width_chars(4)
     self._num_label.get_style_context().add_class("dim-label")
     self.update_number_label()
     self.__menu_button = Gtk.Button.new()
     self.__menu_button.set_relief(Gtk.ReliefStyle.NONE)
     self.__menu_button.get_style_context().add_class("menu-button")
     self.__menu_button.get_style_context().add_class("track-menu-button")
     if list_type & (RowListType.READ_ONLY | RowListType.POPOVER):
         self.__menu_button.set_opacity(0)
         self.__menu_button.set_sensitive(False)
     self._grid.add(self._num_label)
     self._grid.add(self._title_label)
     if self._artists_label is not None:
         self._grid.add(self._artists_label)
     self._grid.add(self._duration_label)
     self._grid.add(self.__menu_button)
     self.add(self._row_widget)
     self.get_style_context().add_class("trackrow")