emmental/audio/scale.py

133 lines
3.9 KiB
Python

# Copyright 2021 (c) Anna Schumaker.
from gi.repository import GLib
from gi.repository import Gtk
from gi.repository import Gst
class ScalePlus(Gtk.Scale):
def __init__(self, min, max, step, page):
Gtk.Scale.__init__(self)
self.set_range(min, max)
self.set_increments(step, page)
self.set_value(min)
self.set_draw_value(True)
self.set_hexpand(True)
self.set_format_value_func(self.format_value)
def __change_value__(self, n, scroll):
value = self.get_value()
self.set_value(value + n)
new = self.get_value()
if value == new:
return None
self.emit("change-value", scroll, new)
return new
def decrement(self):
adjustment = self.get_adjustment()
return self.__change_value__(-adjustment.get_step_increment(),
Gtk.ScrollType.STEP_BACKWARD)
def increment(self):
adjustment = self.get_adjustment()
return self.__change_value__(adjustment.get_step_increment(),
Gtk.ScrollType.STEP_FORWARD)
def format_value(self, scale, value):
return str(value)
class SeekScale(ScalePlus):
def __init__(self, player):
ScalePlus.__init__(self, 0, player.duration,
5 * Gst.SECOND, 30 * Gst.SECOND)
self.set_size_request(200, -1)
self.player = player
self.player.connect("duration-changed", self.duration_changed)
self.player.connect("position-changed", self.position_changed)
def do_change_value(self, scroll, value):
self.player.position = value
def duration_changed(self, player):
self.set_range(0, player.duration)
def position_changed(self, player):
self.set_value(player.position)
def format_value(self, scale, value):
position = int(value / Gst.SECOND)
duration = int(self.get_adjustment().get_upper() / Gst.SECOND)
(p_m, p_s) = divmod(position, 60)
(r_m, r_s) = divmod(duration - position, 60)
return f"{p_m:02}:{p_s:02} / {r_m:02}:{r_s:02}"
class AutoPauseScale(ScalePlus):
def __init__(self):
ScalePlus.__init__(self, -1, 99, 1, 5)
self.keep_playing = True
self.set_digits(0)
def about_to_pause(self):
return self.get_value() == 0
def format_value(self, scale, value):
match int(value):
case -1: return "Keep Playing"
case 0: return "This Track"
case 1: return "Next Track"
case _: return f"{int(value)} Tracks"
def decrement(self):
self.keep_playing = not self.about_to_pause()
super().decrement()
class VolumeScale(ScalePlus):
def __init__(self, player):
ScalePlus.__init__(self, 0.0, 1.0, 0.05, 0.25)
self.player = player
self.set_value(player.volume)
def do_change_value(self, scroll, value):
self.set_value(value)
self.player.volume = value
def format_value(self, scale, value):
return f"{int(value * 100)}%"
class ScaleButton(Gtk.Button):
def __init__(self, scale, icon):
Gtk.Button.__init__(self)
self.add_css_class("normal-icons")
self.add_css_class("flat")
self.set_valign(Gtk.Align.END)
self.set_icon_name(icon)
self.scale = scale
class DecrementButton(ScaleButton):
def __init__(self, scale):
ScaleButton.__init__(self, scale, "list-remove-symbolic")
def do_clicked(self):
self.scale.decrement()
class IncrementButton(ScaleButton):
def __init__(self, scale):
ScaleButton.__init__(self, scale, "list-add-symbolic")
def do_clicked(self):
self.scale.increment()
class ScaleButtonBox(Gtk.Box):
def __init__(self, scale):
Gtk.Box.__init__(self)
self.set_orientation(Gtk.Orientation.HORIZONTAL)
self.append(DecrementButton(scale))
self.append(scale)
self.append(IncrementButton(scale))