emmental/emmental/tracklist/trackview.py
Anna Schumaker a6f59d9378 tracklist: Add an Add Tracks button to the TrackView OSD
The Add Tracks button is a popover button configured to display a list
of playlists that tracks could be added to. I take some extra care to
make sure we only display playlists that have their user-tracks property
set to True, and to hide the currently visible playlist from the list.

Additionally, I create a horizontal size group so the Add and Remove
buttons are the same size.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2023-05-10 17:42:27 -04:00

110 lines
5.1 KiB
Python

# Copyright 2022 (c) Anna Schumaker.
"""A Gtk.ColumnView for displaying Tracks."""
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
from .. import db
from .. import factory
from .. import playlist
from . import row
from . import selection
class TrackView(Gtk.Frame):
"""A Gtk.ColumnView that has been configured to show Tracks."""
playlist = GObject.Property(type=playlist.playlist.Playlist)
n_tracks = GObject.Property(type=int)
runtime = GObject.Property(type=float)
n_selected = GObject.Property(type=int)
have_selected = GObject.Property(type=bool, default=False)
def __init__(self, sql: db.Connection, **kwargs):
"""Initialize a TrackView."""
super().__init__(**kwargs)
self._filtermodel = Gtk.FilterListModel(filter=sql.tracks.get_filter(),
incremental=True)
self._selection = Gtk.MultiSelection(model=self._filtermodel)
self._columnview = Gtk.ColumnView(hexpand=True, vexpand=True,
show_row_separators=True,
enable_rubberband=True,
model=self._selection)
self._scrollwin = Gtk.ScrolledWindow(child=self._columnview)
self._osd = selection.OSD(sql, self._selection, child=self._scrollwin)
self.__append_column("Art", "cover", row.AlbumCover, resizable=False)
self.__append_column("Fav", "favorite", row.FavoriteButton,
resizable=False)
self.__append_column("Track", "number", row.TracknoString,
width=55, xalign=1.0, numeric=True)
self.__append_column("Title", "title", row.TrackString, width=300)
self.__append_column("Length", "length", row.LengthString,
xalign=1.0, numeric=True)
self.__append_column("Artist", "artist", row.TrackString, width=250)
self.__append_column("Album", "name", row.MediumString, width=350)
self.__append_column("Album Artist", "artist", row.AlbumString,
width=250, visible=False)
self.__append_column("Release", "release", row.AlbumString,
width=115, numeric=True)
self.__append_column("Play Count", "playcount", row.PlayCountString,
width=135, numeric=True)
self.__append_column("Last Started", "laststarted",
row.TimestampString, width=250,
visible=False, numeric=True)
self.__append_column("Last Played", "lastplayed",
row.TimestampString, width=250, numeric=True)
self.__append_column("Filepath", "path", row.PathString, visible=False)
self.bind_property("playlist", self._filtermodel, "model")
self.bind_property("playlist", self._osd, "playlist")
self._osd.bind_property("have-selected", self, "have-selected")
self._osd.bind_property("n-selected", self, "n-selected")
self._selection.bind_property("n-items", self, "n-tracks")
self._selection.connect("items-changed", self.__runtime_changed)
self._columnview.connect("activate", self.__track_activated)
self._columnview.add_css_class("emmental-track-list")
self.set_child(self._osd)
def __append_column(self, title: str, property: str, row_type: type,
*, width: int = -1, visible: bool = True,
resizable: bool = True, **kwargs) -> None:
fctry = factory.Factory(row_type=row_type, property=property, **kwargs)
col = Gtk.ColumnViewColumn(title=title, factory=fctry, visible=visible,
resizable=resizable, fixed_width=width)
self._columnview.append_column(col)
def __runtime_changed(self, selection: Gtk.MultiSelection,
position: int, removed: int, added: int) -> None:
self.runtime = sum(t.length for t in self._selection)
def __track_activated(self, columnview: Gtk.ColumnView,
position: int) -> None:
self.playlist.request_track(self._selection[position])
self._selection.unselect_all()
def scroll_to_track(self, track: db.tracks.Track) -> None:
"""Scroll to the requested Track."""
# This is a workaround until the ColumnView has better scrolling
# support, which seems to be targeted for Gtk 4.10.
adjustment = self._scrollwin.get_vadjustment()
for (i, t) in enumerate(self._selection):
if t == track:
pos = max(i - 3, 0) * adjustment.get_upper()
adjustment.set_value(pos / self._selection.get_n_items())
def clear_selected_tracks(self) -> None:
"""Clear the currently selected tracks."""
self._osd.clear_selection()
def reset_osd(self) -> None:
"""Reset the OSD."""
self._osd.reset()
@GObject.Property(type=Gio.ListModel)
def columns(self) -> Gio.ListModel:
"""Get the ListModel for the columns."""
return self._columnview.get_columns()