211 lines
8.0 KiB
Python
211 lines
8.0 KiB
Python
# 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 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",
|
|
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",
|
|
inactive_icon_name="media-playlist-repeat",
|
|
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
|
|
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",
|
|
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 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",
|
|
large_icon=False, 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
|
|
|
|
|
|
class SortRow(factory.ListRow):
|
|
"""A row for managing Sort Order."""
|
|
|
|
def __init__(self, listitem: Gtk.ListItem):
|
|
"""Initialize a Sort Row."""
|
|
super().__init__(listitem=listitem, child=SortFieldWidget())
|
|
|
|
def do_bind(self) -> None:
|
|
"""Bind Sort Field properties to the Widget."""
|
|
self.child.set_sort_field(self.item)
|
|
|
|
def do_unbind(self) -> None:
|
|
"""Unbind properties from the widget."""
|
|
self.child.set_sort_field(None)
|
|
|
|
|
|
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(),
|
|
icon_name="view-list-ordered-symbolic", **kwargs)
|
|
self._selection = Gtk.NoSelection(model=self.model)
|
|
self._factory = factory.Factory(row_type=SortRow)
|
|
self.popover_child = Gtk.ListView(model=self._selection,
|
|
factory=self._factory,
|
|
show_separators=True)
|
|
self.model.bind_property("sort-order", self, "sort-order")
|
|
|
|
def set_sort_order(self, newval: str) -> None:
|
|
"""Directly set the sort order."""
|
|
self.model.set_sort_order(newval)
|