162 lines
6.6 KiB
Python
162 lines
6.6 KiB
Python
# 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,
|
|
"<Control>slash"),
|
|
ActionEntry("clear-selected-tracks", self._unselect.activate,
|
|
"Escape", enabled=(self._unselect, "sensitive")),
|
|
ActionEntry("cycle-loop", self._loop.activate,
|
|
"<Control>l", enabled=(self._top_right,
|
|
"sensitive")),
|
|
ActionEntry("toggle-shuffle", self._shuffle.activate,
|
|
"<Control>s", enabled=(self._top_right,
|
|
"sensitive"))] + \
|
|
self._osd.accelerators
|