emmental/emmental/nowplaying/autopause.py

137 lines
5.0 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)
def decrement(self) -> None:
"""Decrease the autopause count by 1."""
if self.value > -1:
self.value -= 1
def increment(self) -> None:
"""Increase the autopause count by 1."""
if self.value < 99:
self.value += 1
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>")
def decrement(self) -> None:
"""Decrease the autopause value."""
self.popover_child.decrement()
def increment(self) -> None:
"""Increase the autopause value."""
self.popover_child.increment()