# Copyright 2022 (c) Anna Schumaker. """Extra buttons for the TrackList.""" from gi.repository import GObject from gi.repository import Gio from gi.repository import Gtk from . import sorter from .. import buttons from .. import factory class VisibleSwitch(factory.ListRow): """A list row containing a Gtk.Switch.""" def __init__(self, listitem: Gtk.ListItem): """Initialize a VisibleSwitch ListRow.""" super().__init__(listitem=listitem, child=Gtk.Switch()) def do_bind(self) -> None: """Bind the visible property to the switch active property.""" self.bind_and_set_property("visible", "active", bidirectional=True) class VisibleColumns(buttons.PopoverButton): """Shows a Popover Menu to select which columns are visible.""" columns = GObject.Property(type=Gio.ListModel) def __init__(self, columns: Gio.ListModel, **kwargs): """Initialize the VisibleColumns button.""" super().__init__(columns=columns, icon_name="columns-symbolic", has_frame=False, **kwargs) self._selection = Gtk.NoSelection(model=self.columns) self.popover_child = Gtk.ColumnView(model=self._selection, show_row_separators=True) self.__append_column(factory.InscriptionFactory("title"), "Column", width=125) self.__append_column(factory.Factory(row_type=VisibleSwitch), "Visible") self.popover_child.add_css_class("data-table") def __append_column(self, factory: factory.Factory, title: str, *, width: int = -1) -> None: column = Gtk.ColumnViewColumn(factory=factory, title=title, fixed_width=width) self.popover_child.append_column(column) class LoopButton(buttons.ImageToggle): """A button for setting Loop state of a Playlist.""" can_disable = GObject.Property(type=bool, default=True) def __init__(self, **kwargs): """Initialize a Loop Button.""" super().__init__(active_icon_name="media-playlist-repeat-song", inactive_icon_name="media-playlist-repeat", icon_size=Gtk.IconSize.NORMAL, state="None", has_frame=False, **kwargs) def do_clicked(self): """Cycle though Loop states.""" match (self.state, self.can_disable): case ("None", _): self.state = "Playlist" case ("Playlist", _): self.state = "Track" case ("Track", True): self.state = "None" case ("Track", False): self.state = "Playlist" @GObject.Property(type=str) def state(self) -> str: """Get the current state of the button.""" match (self.active, self.icon_opacity): case (True, 1.0): return "Track" case (False, 1.0): return "Playlist" case (_, _): return "None" @state.setter def state(self, newval: str) -> None: match (newval, self.can_disable): case ("None", True): self.active = False self.icon_opacity = 0.5 case ("Playlist", _): self.active = False self.icon_opacity = 1.0 case ("Track", _): self.active = True self.icon_opacity = 1.0 class ShuffleButton(buttons.ImageToggle): """A button for setting Shuffle state of a Playlist.""" def __init__(self, **kwargs): """Initialize a Shuffle Button.""" super().__init__(active_icon_name="media-playlist-shuffle", inactive_icon_name="media-playlist-consecutive", icon_size=Gtk.IconSize.NORMAL, icon_opacity=0.5, has_frame=False, **kwargs) def do_toggled(self): """Adjust opacity when active state toggles.""" self.icon_opacity = 1.0 if self.active else 0.5 class SortFieldWidget(Gtk.Box): """A Widget to display in the Sort Order button popover.""" sort_field = GObject.Property(type=sorter.SortField) def __init__(self) -> None: """Initialize a SortField Widget.""" super().__init__(spacing=6) self._enabled = Gtk.Switch(valign=Gtk.Align.CENTER) self._name = Gtk.Label(hexpand=True, sensitive=False) self._reverse = buttons.ImageToggle("arrow1-up", "arrow1-down", icon_size=Gtk.IconSize.NORMAL, sensitive=False) self._box = Gtk.Box(sensitive=False) self._move_up = Gtk.Button(icon_name="go-up-symbolic") self._move_down = Gtk.Button(icon_name="go-down-symbolic") self._enabled.bind_property("active", self._name, "sensitive") self._enabled.bind_property("active", self._reverse, "sensitive") self._enabled.bind_property("active", self._box, "sensitive") self._enabled.connect("notify::active", self.__notify_enabled) self._reverse.connect("clicked", self.__reverse) self._move_up.connect("clicked", self.__move_item_up) self._move_down.connect("clicked", self.__move_item_down) self.append(self._enabled) self.append(self._name) self.append(self._reverse) self.append(self._box) self._box.append(self._move_up) self._box.append(self._move_down) self._box.add_css_class("linked") def __move_item_down(self, button: Gtk.Button) -> None: if self.sort_field is not None: self.sort_field.move_down() def __move_item_up(self, button: Gtk.Button) -> None: if self.sort_field is not None: self.sort_field.move_up() def __notify_enabled(self, switch: Gtk.Switch, param) -> None: if self.sort_field is not None: if switch.get_active(): self.sort_field.enable() else: self.sort_field.disable() def __reverse(self, button: buttons.ImageToggle) -> None: if self.sort_field is not None: self.sort_field.reverse() def set_sort_field(self, field: sorter.SortField | None) -> None: """Set the Sort Field displayed by this Widget.""" self.sort_field = field self._name.set_text(field.name if field is not None else "") self._enabled.set_active(field is not None and field.enabled) self._reverse.active = field is not None and field.reversed