119 lines
4.5 KiB
Python
119 lines
4.5 KiB
Python
# Copyright 2022 (c) Anna Schumaker.
|
|
"""Widgets for configuring autopause."""
|
|
import re
|
|
from gi.repository import GObject
|
|
from gi.repository import GLib
|
|
from gi.repository import Gtk
|
|
from .. import buttons
|
|
|
|
|
|
class Entry(Gtk.Entry):
|
|
"""A custom SpinButton so we can format output in Python."""
|
|
|
|
value = GObject.Property(type=int, default=-1, minimum=-1, maximum=99)
|
|
|
|
def __init__(self):
|
|
"""Initialize a Spin button."""
|
|
super().__init__(max_width_chars=20, placeholder_text="Keep playing",
|
|
primary_icon_sensitive=False,
|
|
primary_icon_name="list-remove-symbolic",
|
|
secondary_icon_name="list-add-symbolic")
|
|
self._timeout = (None, None)
|
|
#
|
|
self.connect("activate", self.__parse_text)
|
|
self.connect("icon_press", self.__icon_press)
|
|
self.connect("icon_release", self.__icon_release)
|
|
self.connect("notify::value", self.__update_text)
|
|
|
|
self.add_css_class("card")
|
|
|
|
def __set_value(self, newval: int) -> bool:
|
|
if -1 <= newval <= 99:
|
|
self.value = newval
|
|
return True
|
|
return False
|
|
|
|
def __parse_text(self, entry: Gtk.Entry) -> None:
|
|
if parse := re.search(r"this|next|cancel|-?\d+",
|
|
entry.get_text(), re.I):
|
|
match parse.group().lower():
|
|
case "cancel": self.__set_value(-1)
|
|
case "this": self.__set_value(0)
|
|
case "next": self.__set_value(1)
|
|
case _: self.__set_value(int(parse.group()))
|
|
self.delete_text(0, -1)
|
|
|
|
def __change_value(self, change_how: str) -> bool:
|
|
match change_how:
|
|
case "increment": status = self.__set_value(self.value + 1)
|
|
case "decrement": status = self.__set_value(self.value - 1)
|
|
|
|
if not status:
|
|
self._timeout = (None, None)
|
|
elif self._timeout[1] == 150:
|
|
return GLib.SOURCE_CONTINUE
|
|
else:
|
|
timeout_id = GLib.timeout_add(150, self.__change_value, change_how)
|
|
self._timeout = (timeout_id, 150)
|
|
return GLib.SOURCE_REMOVE
|
|
|
|
def __icon_press(self, entry: Gtk.Entry,
|
|
icon_pos: Gtk.EntryIconPosition) -> None:
|
|
self.__icon_release(entry, icon_pos)
|
|
|
|
match icon_pos:
|
|
case Gtk.EntryIconPosition.SECONDARY:
|
|
change_how = "increment"
|
|
self.value += 1
|
|
case Gtk.EntryIconPosition.PRIMARY:
|
|
change_how = "decrement"
|
|
self.value -= 1
|
|
|
|
timeout_id = GLib.timeout_add(500, self.__change_value, change_how)
|
|
self._timeout = (timeout_id, 500)
|
|
|
|
def __icon_release(self, entry: Gtk.Entry,
|
|
icon_pos: Gtk.EntryIconPosition) -> None:
|
|
if self._timeout != (None, None):
|
|
GLib.source_remove(self._timeout[0])
|
|
self._timeout = (None, None)
|
|
|
|
def __update_text(self, spin, param) -> None:
|
|
match self.value:
|
|
case -1: text = "Keep playing"
|
|
case 0: text = "Pause after this track"
|
|
case 1: text = "Pause after the next track"
|
|
case _: text = f"Pause after {self.value} tracks"
|
|
|
|
self.set_placeholder_text(text)
|
|
self.set_icon_sensitive(Gtk.EntryIconPosition.PRIMARY,
|
|
self.value > -1)
|
|
self.set_icon_sensitive(Gtk.EntryIconPosition.SECONDARY,
|
|
self.value < 99)
|
|
|
|
|
|
class Button(buttons.PopoverButton):
|
|
"""A PopoverButton that displays Autopause count."""
|
|
|
|
value = GObject.Property(type=int, default=-1, minimum=-1, maximum=99)
|
|
|
|
def __init__(self, **kwargs):
|
|
"""Initialize an Autopause Button."""
|
|
super().__init__(popover_child=Entry(), **kwargs)
|
|
self._arrow = Gtk.Image(icon_name="pan-down-symbolic", margin_top=6)
|
|
self._count = Gtk.Label(yalign=0, halign=Gtk.Align.CENTER,
|
|
margin_top=3)
|
|
self._overlay = Gtk.Overlay(child=self._arrow)
|
|
|
|
self._overlay.add_overlay(self._count)
|
|
self.bind_property("value", self.popover_child, "value",
|
|
GObject.BindingFlags.BIDIRECTIONAL)
|
|
self.connect("notify::value", self.__notify_value)
|
|
|
|
self._count.set_markup("<small></small>")
|
|
self.set_child(self._overlay)
|
|
|
|
def __notify_value(self, button: buttons.PopoverButton, param) -> None:
|
|
text = str(self.value) if self.value > -1 else ""
|
|
self._count.set_markup(f"<small>{text}</small>")
|