# 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))