#!/usr/bin/python3 from PyQt6.QtCore import Qt, QTimer from PyQt6.QtGui import QMouseEvent from PyQt6.QtWidgets import QSlider, QStyle, QStyleOptionSlider PROGRESS_UPDATE_RATE = 60 PROGRESS_UPDATE_INTERVAL = 1000 // PROGRESS_UPDATE_RATE class TrackProgressSlider(QSlider): def __init__(self, app, parent=None): super().__init__(Qt.Orientation.Horizontal, parent) self.app = app self.track_control = None self.dragged = False self.progress_update_timer = QTimer() self.progress_update_timer.timeout.connect(self.update_progress) self.progress_update_timer.start(PROGRESS_UPDATE_INTERVAL) option = QStyleOptionSlider() style = self.style() self.handle_width = style.pixelMetric(QStyle.PixelMetric.PM_SliderThickness, option, self) self.sliderPressed.connect(self.on_press) self.sliderReleased.connect(self.on_release) def late_init(self): self.track_control = self.app.gui.track_control def mousePressEvent(self, event: QMouseEvent): # we need a custom press event bc. PyQt doesn't set the slider position when clicked if event.button() == Qt.MouseButton.LeftButton: event.accept() x = event.pos().x() # old value calculation: # value = self.maximum() * x // self.width() # but we need that new calculation because the handle width is limiting the range, and we need to set # the slider handle's center to the click position, not to the start of the handle # (self.width() - self.handle_width) calculates the usable width and # (x - self.handle_width // 2) offsets the position by minus half of the handle width value = self.maximum() * (x - self.handle_width // 2) // (self.width() - self.handle_width) self.setValue(value) return super().mousePressEvent(event) def on_press(self): self.dragged = True def on_release(self): self.dragged = False if self.app.player.current_playlist.has_tracks(): self.app.player.seek(self.value()) def update_progress(self): if not self.dragged: if self.app.player.playing: remaining = self.app.player.track_progress.timer.remainingTime() if remaining == -1: remaining = self.app.player.track_progress.remaining_time track_duration = self.app.player.current_playlist.current_track.duration progress = track_duration - remaining self.track_control.progress_indicator.setText(self.app.utils.format_time(progress)) self.track_control.track_progress_slider.setValue(progress) else: self.track_control.progress_indicator.setText(self.app.utils.format_time(0)) self.track_control.track_progress_slider.setValue(0)