# Copyright 2022 (c) Anna Schumaker. """A card for displaying a list of tracks.""" from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio from gi.repository import Gtk from ..action import ActionEntry from ..playlist.playlist import Playlist from ..playlist.previous import Previous from .. import db from .. import entry from . import buttons from . import footer from . import selection from . import trackview class Card(Gtk.Box): """Our Tracklist.""" sql = GObject.Property(type=db.Connection) def __init__(self, sql: db.Connection, **kwargs): """Set up the Tracklist widget.""" super().__init__(sql=sql, orientation=Gtk.Orientation.VERTICAL, **kwargs) self._top_left = Gtk.Box() self._top_right = Gtk.Box(sensitive=False) self._top_box = Gtk.CenterBox(margin_start=6, margin_end=6) self._filter = entry.Filter("tracks", hexpand=True, margin_start=100, margin_end=100) self._trackview = trackview.TrackView(sql) self._osd = selection.OSD(sql, self._trackview.selection_model, child=self._trackview) self._visible_cols = buttons.VisibleColumns(self._trackview.columns) self._unselect = Gtk.Button(icon_name="edit-select-none-symbolic", tooltip_text="unselect all tracks", has_frame=False, sensitive=False) self._loop = buttons.LoopButton() self._shuffle = buttons.ShuffleButton() self._sort = buttons.SortButton() self._footer = footer.Footer(margin_start=6, margin_end=6, margin_top=6, margin_bottom=6) self._top_left.append(self._visible_cols) self._top_left.append(self._unselect) self._top_right.append(self._loop) self._top_right.append(self._shuffle) self._top_right.append(self._sort) self._top_box.set_start_widget(self._top_left) self._top_box.set_center_widget(self._filter) self._top_box.set_end_widget(self._top_right) self.append(self._top_box) self.append(Gtk.Separator()) self.append(self._osd) self.append(Gtk.Separator()) self.append(self._footer) self._osd.bind_property("have-selected", self._trackview, "have-selected") self._osd.bind_property("n-selected", self._trackview, "n-selected") self._trackview.bind_property("n-tracks", self._footer, "count") self._trackview.bind_property("n-selected", self._footer, "selected") self._trackview.bind_property("runtime", self._footer, "runtime") self._trackview.bind_property("have-selected", self._unselect, "sensitive") self._filter.connect("search-changed", self.__search_changed) self._unselect.connect("clicked", self._osd.clear_selection) self._loop.connect("notify::state", self.__update_loop_state) self._shuffle.connect("notify::active", self.__update_shuffle_state) self._sort.connect("notify::sort-order", self.__update_sort_order) self._top_box.add_css_class("toolbar") self.add_css_class("card") def __playlist_notify(self, playlist: Playlist, param) -> None: match param.name: case "loop": self._loop.state = playlist.loop case "playlist": self.__set_button_state() case "shuffle": self._shuffle.active = playlist.shuffle case "sort-order": self._sort.sort_order = playlist.sort_order def __set_button_state(self) -> None: can_disable = self.playlist.playlist != self.sql.playlists.collection self._loop.can_disable = can_disable self._loop.state = self.playlist.loop self._shuffle.active = self.playlist.shuffle self._sort.set_sort_order(self.playlist.sort_order) self._osd.reset() def __update_loop_state(self, loop: buttons.LoopButton, param) -> None: if self.playlist.loop != loop.state: self.playlist.loop = loop.state def __update_shuffle_state(self, shuffle: buttons.ShuffleButton, param) -> None: if self.playlist.shuffle != shuffle.active: self.playlist.shuffle = shuffle.active def __update_sort_order(self, sort: buttons.SortButton, param) -> None: if self.playlist.sort_order != sort.sort_order: self.playlist.sort_order = sort.sort_order def __search_changed(self, filter: entry.Filter) -> None: self.sql.tracks.filter(filter.get_query()) def __scroll_idle(self, track: db.tracks.Track) -> bool: self._trackview.scroll_to_track(track) return GLib.SOURCE_REMOVE def scroll_to_track(self, track: db.tracks.Track) -> None: """Scroll to the requested Track.""" if self.playlist is not None: GLib.idle_add(self.__scroll_idle, track) @GObject.Property(type=Gio.ListModel) def columns(self) -> Gio.ListModel: """Get the columns displayed in the Tracklist.""" return self._trackview.columns @GObject.Property(type=Playlist) def playlist(self) -> Playlist: """Get the currently visible Playlist.""" return self._trackview.playlist @playlist.setter def playlist(self, newval: Playlist) -> None: if self._trackview.playlist is not None: self._trackview.playlist.disconnect_by_func(self.__playlist_notify) self._trackview.playlist = newval self._osd.playlist = newval if newval is not None: self._top_right.set_sensitive(not isinstance(newval, Previous)) self.__set_button_state() newval.connect("notify", self.__playlist_notify) @property def accelerators(self) -> list[ActionEntry]: """Get a list of accelerators for the Tracklist.""" return [ActionEntry("focus-search-track", self._filter.grab_focus, "slash"), ActionEntry("clear-selected-tracks", self._unselect.activate, "Escape", enabled=(self._unselect, "sensitive")), ActionEntry("cycle-loop", self._loop.activate, "l", enabled=(self._top_right, "sensitive")), ActionEntry("toggle-shuffle", self._shuffle.activate, "s", enabled=(self._top_right, "sensitive"))] + \ self._osd.accelerators