Add video scrubbing and click to seek/change volume on sliders

This commit is contained in:
Peter Stockings
2026-03-03 23:53:27 +11:00
parent e120813a01
commit c4bef281f7

View File

@@ -2,7 +2,7 @@ import os
import datetime
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QFrame, QSlider, QTextEdit, QApplication
QPushButton, QFrame, QSlider, QTextEdit, QApplication, QToolTip
)
from PyQt6.QtCore import Qt, pyqtSignal, QTimer
from PyQt6.QtGui import QIcon
@@ -10,6 +10,49 @@ import uuid
from vlc_player import VLCSyncPlayer
class ClickableSlider(QSlider):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._get_tooltip_text = None
def set_tooltip_provider(self, provider_func):
self._get_tooltip_text = provider_func
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == Qt.MouseButton.LeftButton:
val = 0
if self.orientation() == Qt.Orientation.Horizontal:
if self.width() > 0:
val = self.minimum() + ((self.maximum() - self.minimum()) * event.pos().x()) / self.width()
else:
if self.height() > 0:
val = self.minimum() + ((self.maximum() - self.minimum()) * (self.height() - event.pos().y())) / self.height()
val = max(self.minimum(), min(self.maximum(), int(val)))
self.setValue(val)
self.sliderMoved.emit(val)
if self._get_tooltip_text:
text = self._get_tooltip_text(val)
if text:
QToolTip.showText(event.globalPosition().toPoint(), text, self)
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
if event.buttons() & Qt.MouseButton.LeftButton:
if self._get_tooltip_text:
text = self._get_tooltip_text(self.value())
if text:
QToolTip.showText(event.globalPosition().toPoint(), text, self)
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
if event.button() == Qt.MouseButton.LeftButton:
# Explicitly emit sliderReleased on mouse release
# to ensure single clicks on the track also trigger the release logic
self.sliderReleased.emit()
class ExpectedVlcEvent:
def __init__(self, action: str, req_id: str, target_val=None):
self.action = action
@@ -90,23 +133,25 @@ class RoomWidget(QWidget):
self.play_btn.setObjectName("playBtn")
# Time and SeekBar
self.seekbar = QSlider(Qt.Orientation.Horizontal)
self.seekbar = ClickableSlider(Qt.Orientation.Horizontal)
self.seekbar.setRange(0, 1000)
self.seekbar.setObjectName("seekBar")
self.seekbar.sliderMoved.connect(self.on_seekbar_dragged)
self.seekbar.sliderReleased.connect(self.on_seekbar_released)
self.seekbar.set_tooltip_provider(self.get_seekbar_tooltip)
self.time_lbl = QLabel("00:00:00 / 00:00:00")
# Volume
self.vol_icon = QLabel("🔊")
self.vol_icon.setObjectName("volIcon")
self.volume_slider = QSlider(Qt.Orientation.Horizontal)
self.volume_slider = ClickableSlider(Qt.Orientation.Horizontal)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(100)
self.volume_slider.setFixedWidth(100)
self.volume_slider.setObjectName("volumeSlider")
self.volume_slider.valueChanged.connect(self.on_volume_changed)
self.volume_slider.set_tooltip_provider(lambda v: f"{v}%")
# Fullscreen
self.fullscreen_btn = QPushButton("")
@@ -172,6 +217,14 @@ class RoomWidget(QWidget):
self.play_btn.clicked.connect(self.toggle_playback)
def get_seekbar_tooltip(self, value):
length_ms = self.vlc_player.get_length()
if length_ms > 0:
target_ms = int((value / 1000.0) * length_ms)
s = max(0, target_ms) // 1000
return f"{s//3600:02d}:{(s%3600)//60:02d}:{s%60:02d}"
return ""
def setup_room(self, room_code: str, username: str, file_name: str, file_path: str, start_time_s: float = 0.0):
self.room_code = room_code
self.username = username
@@ -313,6 +366,8 @@ class RoomWidget(QWidget):
s = max(0, ms) // 1000
return f"{s//3600:02d}:{(s%3600)//60:02d}:{s%60:02d}"
self.time_lbl.setText(f"{fmt(target_ms)} / {fmt(length_ms)}")
# Scrub the video locally in real-time
self._tell_vlc_and_expect("seek", target_ms / 1000.0)
def on_seekbar_released(self):
length_ms = self.vlc_player.get_length()