# Copyright 2022 (c) Anna Schumaker. """Widgets for sidebar rows.""" from gi.repository import GObject from gi.repository import Gtk from .title import PlaylistTitle from .title import EditableTitle from .icon import Icon from .icon import Settable from .. import db from .. import factory class BaseRow(Gtk.Box): """Base class for Row widgets.""" playlist = GObject.Property(type=db.playlist.Playlist) name = GObject.Property(type=str) count = GObject.Property(type=int) class Row(BaseRow): """A basic row representing a playlist without extra actions.""" image = GObject.Property(type=GObject.TYPE_PYOBJECT) def __init__(self, **kwargs): """Initialize a sidebar Row.""" super().__init__(spacing=12, **kwargs) self._icon = Icon(text=self.name, show_initials=True) self._title = PlaylistTitle(title=self.name, count=self.count) self._year = None self.bind_property("image", self._icon, "filepath") self.bind_property("name", self._icon, "text") self.bind_property("name", self._title, "title") self.bind_property("count", self._title, "count") self.append(self._icon) self.append(self._title) @GObject.Property(type=int) def year(self) -> int | None: """Set the year displayed in the icon.""" return self._year @year.setter def year(self, year: int) -> None: digits = str(year) self._year = year self._icon.text = f"{digits[-2]} {digits[-1]}" class PlaylistRow(BaseRow): """An advanced playlist row with extra actions for users.""" icon_name = GObject.Property(type=str) filepath = GObject.Property(type=GObject.TYPE_PYOBJECT) modifiable = GObject.Property(type=bool, default=False) def __init__(self, **kwargs): """Initialize a PlaylistRow.""" super().__init__(**kwargs) self._icon = Settable() self._title = EditableTitle(margin_start=12, margin_end=12) self._delete = Gtk.Button(icon_name="big-x-symbolic", tooltip_text="delete playlist", valign=Gtk.Align.CENTER, has_frame=False, visible=False) self.bind_property("name", self._icon, "text") self.bind_property("icon-name", self._icon, "icon-name") self.bind_property("filepath", self._icon, "filepath", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("modifiable", self._icon, "settable") self.bind_property("name", self._title, "title") self.bind_property("count", self._title, "count") self.bind_property("modifiable", self._title, "editable") self.bind_property("modifiable", self._delete, "visible") self._title.connect("request-rename", self.__on_rename) self._delete.connect("clicked", self.__on_delete) self._delete.add_css_class("emmental-delete") self.append(self._icon) self.append(self._title) self.append(self._delete) def __on_rename(self, title: EditableTitle, new_name: str) -> None: if self.playlist is not None: self.playlist.rename(new_name) def __on_delete(self, button: Gtk.Button) -> None: if self.playlist is not None: self.playlist.delete() class LibraryRow(BaseRow): """An advaced playlist row with extra actions for library management.""" enabled = GObject.Property(type=bool, default=True) online = GObject.Property(type=bool, default=True) scanning = GObject.Property(type=bool, default=False) progress = GObject.Property(type=float) def __init__(self, **kwargs): """Initialize a LibraryRow.""" super().__init__(**kwargs) self._box = Gtk.Box() self._overlay = Gtk.Overlay(child=self._box) self._switch = Gtk.Switch(active=self.enabled, valign=Gtk.Align.CENTER, tooltip_text="disable library path") self._title = PlaylistTitle(margin_start=12, margin_end=12) self._scan = Gtk.Button(icon_name="update", has_frame=False, tooltip_text="update library path", valign=Gtk.Align.CENTER) self._stop = Gtk.Button(icon_name="stop-sign-large", has_frame=False, tooltip_text="cancel update", valign=Gtk.Align.CENTER, visible=False) self._delete = Gtk.Button(icon_name="big-x-symbolic", tooltip_text="delete library path", valign=Gtk.Align.CENTER, has_frame=False) self._progress = Gtk.ProgressBar(valign=Gtk.Align.END, visible=False) self.bind_property("enabled", self._switch, "active", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("online", self._switch, "sensitive") self.bind_property("name", self._title, "title") self.bind_property("count", self._title, "count") self.bind_property("online", self._title, "sensitive") self.bind_property("enabled", self._title, "sensitive") self.bind_property("scanning", self._stop, "visible") self.bind_property("scanning", self._scan, "visible", GObject.BindingFlags.INVERT_BOOLEAN) self.bind_property("scanning", self._progress, "visible") self.bind_property("progress", self._progress, "fraction") self._delete.connect("clicked", self.__on_button_press, "delete") self._scan.connect("clicked", self.__on_button_press, "scan") self._stop.connect("clicked", self.__on_button_press, "stop") self._switch.connect("notify::active", self.__on_switch_activated) self._delete.add_css_class("emmental-delete") self._stop.add_css_class("emmental-stop") self._progress.add_css_class("osd") self._box.append(self._switch) self._box.append(self._title) self._box.append(self._scan) self._box.append(self._stop) self._box.append(self._delete) self._overlay.add_overlay(self._progress) self.append(self._overlay) def __on_button_press(self, button: Gtk.Button, action: str) -> None: if self.playlist is not None: match action: case "delete": self.playlist.delete() case "scan": self.playlist.scan() case "stop": self.playlist.stop() def __on_switch_activated(self, switch: Gtk.Switch, param) -> None: state = "disable" if self.enabled else "enable" self._switch.set_tooltip_text(f"{state} library path") class TreeRow(factory.TreeRow): """A factory Row used for displaying individual playlists.""" def do_bind(self) -> None: """Bind a Playlist to this Row.""" self.child.playlist = self.item self.bind_and_set_property("name", "name") self.bind_and_set_property("n-tracks", "count") self.bind_n_children(self.item.children) self.bind_active("active") def do_unbind(self) -> None: """Unbind a Playlist from this Row.""" self.child.playlist = None