# 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("") 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"{text}") def decrement(self) -> None: """Decrease the autopause value.""" self.popover_child.decrement() def increment(self) -> None: """Increase the autopause value.""" self.popover_child.increment()