# 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()