# 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 class VisibleRow(Gtk.ListBoxRow): """A ListBoxRow containing a Gtk.Switch and a title Label.""" active = GObject.Property(type=bool, default=True) title = GObject.Property(type=str) def __init__(self, title: str, active: bool): """Initialize a VisibleRow ListBoxRow.""" super().__init__(title=title, active=active, child=Gtk.Box(margin_start=6, margin_end=6, margin_top=6, margin_bottom=6, spacing=6)) self._switch = Gtk.Switch(active=active) self._label = Gtk.Label.new(title) self.bind_property("active", self._switch, "active", GObject.BindingFlags.BIDIRECTIONAL) self.props.child.append(self._switch) self.props.child.append(self._label) 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", tooltip_text="configure visible columns", has_frame=False, **kwargs) self.popover_child = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE) self.popover_child.bind_model(columns, self.__create_func) self.popover_child.connect("row-activated", self.__row_activated) self.popover_child.add_css_class("boxed-list") def __create_func(self, column: Gtk.ColumnViewColumn) -> VisibleRow: row = VisibleRow(column.get_title(), column.get_visible()) row.bind_property("active", column, "visible", GObject.BindingFlags.BIDIRECTIONAL) return row def __row_activated(self, box: Gtk.ListBox, row: Gtk.ListBoxRow) -> None: row.active = not row.active 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", active_tooltip_text="loop: track", inactive_icon_name="media-playlist-repeat", inactive_tooltip_text="loop: disabled", large_icon=False, 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 self.inactive_tooltip_text = "loop: disabled" case ("Playlist", _): self.active = False self.icon_opacity = 1.0 self.inactive_tooltip_text = "loop: playlist" 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", active_tooltip_text="shuffle: enabled", inactive_icon_name="media-playlist-consecutive", inactive_tooltip_text="shuffle: disabled", large_icon=False, 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 SortRow(Gtk.ListBoxRow): """A ListBoxRow for managing Sort Order.""" active = GObject.Property(type=bool, default=False) sort_field = GObject.Property(type=sorter.SortField) def __init__(self, sort_field: sorter.SortField): """Initialize a Sort Row.""" super().__init__(sort_field=sort_field, active=sort_field.enabled, child=Gtk.Box(margin_start=6, margin_end=6, margin_top=6, margin_bottom=6, spacing=6)) self._switch = Gtk.Switch(active=self.active, valign=Gtk.Align.CENTER) self._label = Gtk.Label(label=sort_field.name, hexpand=True, sensitive=self.active, xalign=0.0) self._reverse = buttons.ImageToggle("arrow1-up", "arrow1-down", active=sort_field.reversed, sensitive=self.active, has_frame=False) self._move_box = Gtk.Box(sensitive=self.active) self._move_up = Gtk.Button(icon_name="go-up-symbolic") self._move_down = Gtk.Button(icon_name="go-down-symbolic") self._switch.connect("notify::active", self.__toggle_enabled) self._reverse.connect("toggled", self.__reverse) self._move_up.connect("clicked", self.__move_up) self._move_down.connect("clicked", self.__move_down) self.props.child.append(self._switch) self.props.child.append(self._label) self.props.child.append(self._reverse) self.props.child.append(self._move_box) self._move_box.append(self._move_up) self._move_box.append(self._move_down) self._move_box.add_css_class("linked") def __toggle_enabled(self, switch: Gtk.Switch, param) -> None: if switch.props.active: self.sort_field.enable() else: self.sort_field.disable() def __reverse(self, button: buttons.ImageToggle) -> None: self.sort_field.reverse() def __move_up(self, button: Gtk.Button) -> None: self.sort_field.move_up() def __move_down(self, button: Gtk.Button) -> None: self.sort_field.move_down() class SortButton(buttons.PopoverButton): """Shows a Popover Menu to sort playlists.""" model = GObject.Property(type=sorter.SortOrderModel) sort_order = GObject.Property(type=str) def __init__(self, **kwargs): """Initialize the Sort button.""" super().__init__(has_frame=False, model=sorter.SortOrderModel(), tooltip_text="configure playlist sort order", icon_name="list-compact-symbolic", **kwargs) self.popover_child = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE) self.popover_child.bind_model(self.model, self.__create_func) self.popover_child.connect("row-activated", self.__row_activated) self.popover_child.add_css_class("boxed-list") self.model.bind_property("sort-order", self, "sort-order") def __create_func(self, sort_field: sorter.SortField) -> SortRow: return SortRow(sort_field) def __row_activated(self, box: Gtk.ListBox, row: SortRow) -> None: if row.active: row._reverse.active = not row.sort_field.reversed else: row.sort_field.enable() def set_sort_order(self, newval: str) -> None: """Directly set the sort order.""" self.model.set_sort_order(newval)